Wikidata language picker

This commit is contained in:
pietervdvn 2022-07-11 09:14:26 +02:00
parent b75581405e
commit 325e30666b
14 changed files with 335 additions and 213 deletions

View file

@ -10,6 +10,7 @@ import Constants from "../Models/Constants";
import {Utils} from "../Utils"; import {Utils} from "../Utils";
import Link from "../UI/Base/Link"; import Link from "../UI/Base/Link";
import {LayoutConfigJson} from "../Models/ThemeConfig/Json/LayoutConfigJson"; import {LayoutConfigJson} from "../Models/ThemeConfig/Json/LayoutConfigJson";
import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson";
export class AllKnownLayouts { export class AllKnownLayouts {
public static allKnownLayouts: Map<string, LayoutConfig> = AllKnownLayouts.AllLayouts(); public static allKnownLayouts: Map<string, LayoutConfig> = AllKnownLayouts.AllLayouts();
@ -209,9 +210,9 @@ export class AllKnownLayouts {
]) ])
} }
private static getSharedLayers(): Map<string, LayerConfig> { public static getSharedLayers(): Map<string, LayerConfig> {
const sharedLayers = new Map<string, LayerConfig>(); const sharedLayers = new Map<string, LayerConfig>();
for (const layer of known_themes.layers) { for (const layer of known_themes["layers"]) {
try { try {
// @ts-ignore // @ts-ignore
const parsed = new LayerConfig(layer, "shared_layers") const parsed = new LayerConfig(layer, "shared_layers")
@ -226,6 +227,16 @@ export class AllKnownLayouts {
return sharedLayers; return sharedLayers;
} }
public static getSharedLayersConfigs(): Map<string, LayerConfigJson> {
const sharedLayers = new Map<string, LayerConfigJson>();
for (const layer of known_themes["layers"]) {
// @ts-ignore
sharedLayers.set(layer.id, layer);
}
return sharedLayers;
}
private static GenerateOrderedList(allKnownLayouts: Map<string, LayoutConfig>): LayoutConfig[] { private static GenerateOrderedList(allKnownLayouts: Map<string, LayoutConfig>): LayoutConfig[] {
const list = [] const list = []
allKnownLayouts.forEach((layout) => { allKnownLayouts.forEach((layout) => {
@ -236,7 +247,7 @@ export class AllKnownLayouts {
private static AllLayouts(): Map<string, LayoutConfig> { private static AllLayouts(): Map<string, LayoutConfig> {
const dict: Map<string, LayoutConfig> = new Map(); const dict: Map<string, LayoutConfig> = new Map();
for (const layoutConfigJson of known_themes.themes) { for (const layoutConfigJson of known_themes["themes"]) {
const layout = new LayoutConfig(<LayoutConfigJson>layoutConfigJson, true) const layout = new LayoutConfig(<LayoutConfigJson>layoutConfigJson, true)
dict.set(layout.id, layout) dict.set(layout.id, layout)
for (let i = 0; i < layout.layers.length; i++) { for (let i = 0; i < layout.layers.length; i++) {

View file

@ -95,9 +95,32 @@ export class AddContextToTranslations<T> extends DesugaringStep<T> {
* ] * ]
* } * }
* rewritten // => expected * rewritten // => expected
*
*
* // Should ignore all if '#dont-translate' is set
* const theme = {
* "#dont-translate": "*",
* layers: [
* {
* builtin: ["abc"],
* override: {
* title:{
* en: "Some title"
* }
* }
* }
* ]
* }
* const rewritten = new AddContextToTranslations<any>("prefix:").convert(theme, "context").result
* rewritten // => theme
*
*/ */
convert(json: T, context: string): { result: T; errors?: string[]; warnings?: string[]; information?: string[] } { convert(json: T, context: string): { result: T; errors?: string[]; warnings?: string[]; information?: string[] } {
if(json["#dont-translate"] === "*"){
return {result: json}
}
const result = Utils.WalkJson(json, (leaf, path) => { const result = Utils.WalkJson(json, (leaf, path) => {
if(leaf === undefined || leaf === null){ if(leaf === undefined || leaf === null){
return leaf return leaf

View file

@ -141,17 +141,21 @@ export class Each<X, Y> extends Conversion<X[], Y[]> {
export class On<P, T> extends DesugaringStep<T> { export class On<P, T> extends DesugaringStep<T> {
private readonly key: string; private readonly key: string;
private readonly step: Conversion<P, P>; private readonly step: ((t: T) => Conversion<P, P>);
constructor(key: string, step: Conversion<P, P>) { constructor(key: string, step: Conversion<P, P> | ((t: T )=> Conversion<P, P>)) {
super("Applies " + step.name + " onto property `"+key+"`", [key], `On(${key}, ${step.name})`); super("Applies " + step.name + " onto property `"+key+"`", [key], `On(${key}, ${step.name})`);
if(typeof step === "function"){
this.step = step; this.step = step;
}else{
this.step = _ => step
}
this.key = key; this.key = key;
} }
convert(json: T, context: string): { result: T; errors?: string[]; warnings?: string[], information?: string[] } { convert(json: T, context: string): { result: T; errors?: string[]; warnings?: string[], information?: string[] } {
json = {...json} json = {...json}
const step = this.step const step = this.step(json)
const key = this.key; const key = this.key;
const value: P = json[key] const value: P = json[key]
if (value === undefined || value === null) { if (value === undefined || value === null) {

View file

@ -12,10 +12,12 @@ import {AddContextToTranslations} from "./AddContextToTranslations";
class ExpandTagRendering extends Conversion<string | TagRenderingConfigJson | { builtin: string | string[], override: any }, TagRenderingConfigJson[]> { class ExpandTagRendering extends Conversion<string | TagRenderingConfigJson | { builtin: string | string[], override: any }, TagRenderingConfigJson[]> {
private readonly _state: DesugaringContext; private readonly _state: DesugaringContext;
private readonly _self: LayerConfigJson;
constructor(state: DesugaringContext) { constructor(state: DesugaringContext, self: LayerConfigJson) {
super("Converts a tagRenderingSpec into the full tagRendering, e.g. by substituting the tagRendering by the shared-question", [], "ExpandTagRendering"); super("Converts a tagRenderingSpec into the full tagRendering, e.g. by substituting the tagRendering by the shared-question", [], "ExpandTagRendering");
this._state = state; this._state = state;
this._self = self;
} }
convert(json: string | TagRenderingConfigJson | { builtin: string | string[]; override: any }, context: string): { result: TagRenderingConfigJson[]; errors: string[]; warnings: string[] } { convert(json: string | TagRenderingConfigJson | { builtin: string | string[]; override: any }, context: string): { result: TagRenderingConfigJson[]; errors: string[]; warnings: string[] } {
@ -33,10 +35,20 @@ class ExpandTagRendering extends Conversion<string | TagRenderingConfigJson | {
if (state.tagRenderings.has(name)) { if (state.tagRenderings.has(name)) {
return [state.tagRenderings.get(name)] return [state.tagRenderings.get(name)]
} }
if (name.indexOf(".") >= 0) { if (name.indexOf(".") < 0) {
return undefined;
}
const spl = name.split("."); const spl = name.split(".");
const layer = state.sharedLayers.get(spl[0]) let layer = state.sharedLayers.get(spl[0])
if (spl.length === 2 && layer !== undefined) { if (spl[0] === this._self.id) {
layer = this._self
}
if (spl.length !== 2 || layer === undefined) {
return undefined
}
const id = spl[1]; const id = spl[1];
const layerTrs = <TagRenderingConfigJson[]>layer.tagRenderings.filter(tr => tr["id"] !== undefined) const layerTrs = <TagRenderingConfigJson[]>layer.tagRenderings.filter(tr => tr["id"] !== undefined)
@ -68,8 +80,6 @@ class ExpandTagRendering extends Conversion<string | TagRenderingConfigJson | {
if (matchingTrs.length !== 0) { if (matchingTrs.length !== 0) {
return matchingTrs return matchingTrs
} }
}
}
return undefined; return undefined;
} }
@ -116,8 +126,21 @@ class ExpandTagRendering extends Conversion<string | TagRenderingConfigJson | {
if (lookup === undefined) { if (lookup === undefined) {
let candidates = Array.from(state.tagRenderings.keys()) let candidates = Array.from(state.tagRenderings.keys())
if (name.indexOf(".") > 0) { if (name.indexOf(".") > 0) {
const [layer, search] = name.split(".") const [layerName, search] = name.split(".")
candidates = Utils.NoNull( state.sharedLayers.get(layer).tagRenderings.map(tr => tr["id"])).map(id => layer+"."+id) let layer = state.sharedLayers.get(layerName)
if (layerName === this._self.id) {
layer = this._self;
}
if (layer === undefined) {
const candidates = Utils.sortedByLevenshteinDistance(layerName, Array.from(state.sharedLayers.keys()), s => s)
if(state.sharedLayers.size === 0){
warnings.push(ctx + ": BOOTSTRAPPING. Rerun generate layeroverview. While reusing tagrendering: " + name + ": layer " + layerName + " not found. Maybe you meant on of " + candidates.slice(0, 3).join(", "))
}else{
errors.push(ctx + ": While reusing tagrendering: " + name + ": layer " + layerName + " not found. Maybe you meant on of " + candidates.slice(0, 3).join(", "))
}
continue
}
candidates = Utils.NoNull(layer.tagRenderings.map(tr => tr["id"])).map(id => layerName + "." + id)
} }
candidates = Utils.sortedByLevenshteinDistance(name, candidates, i => i); candidates = Utils.sortedByLevenshteinDistance(name, candidates, i => i);
errors.push(ctx + ": The tagRendering with identifier " + name + " was not found.\n\tDid you mean one of " + candidates.join(", ") + "?") errors.push(ctx + ": The tagRendering with identifier " + name + " was not found.\n\tDid you mean one of " + candidates.join(", ") + "?")
@ -422,7 +445,8 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
if (foundLanguages.size === 0) { if (foundLanguages.size === 0) {
const args = argNamesList.map(nm => special[nm] ?? "").join(",") const args = argNamesList.map(nm => special[nm] ?? "").join(",")
return {'*': `{${type}(${args})}` return {
'*': `{${type}(${args})}`
} }
} }
@ -492,11 +516,11 @@ export class PrepareLayer extends Fuse<LayerConfigJson> {
"Fully prepares and expands a layer for the LayerConfig.", "Fully prepares and expands a layer for the LayerConfig.",
new On("tagRenderings", new Each(new RewriteSpecial())), new On("tagRenderings", new Each(new RewriteSpecial())),
new On("tagRenderings", new Concat(new ExpandRewrite()).andThenF(Utils.Flatten)), new On("tagRenderings", new Concat(new ExpandRewrite()).andThenF(Utils.Flatten)),
new On("tagRenderings", new Concat(new ExpandTagRendering(state))), new On("tagRenderings", layer => new Concat(new ExpandTagRendering(state, layer))),
new On("mapRendering", new Concat(new ExpandRewrite()).andThenF(Utils.Flatten)), new On("mapRendering", new Concat(new ExpandRewrite()).andThenF(Utils.Flatten)),
new On("mapRendering",new Each( new On("icon", new FirstOf(new ExpandTagRendering(state))))), new On("mapRendering", layer => new Each(new On("icon", new FirstOf(new ExpandTagRendering(state, layer))))),
new SetDefault("titleIcons", ["defaults"]), new SetDefault("titleIcons", ["defaults"]),
new On("titleIcons", new Concat(new ExpandTagRendering(state))) new On("titleIcons", layer => new Concat(new ExpandTagRendering(state, layer)))
); );
} }
} }

View file

@ -508,6 +508,7 @@ export class ValidateLayer extends DesugaringStep<LayerConfigJson> {
const errors = [] const errors = []
const warnings = [] const warnings = []
const information = [] const information = []
context = "While validating a layer: "+context
if (typeof json === "string") { if (typeof json === "string") {
errors.push(context + ": This layer hasn't been expanded: " + json) errors.push(context + ": This layer hasn't been expanded: " + json)
return { return {

View file

@ -236,13 +236,14 @@ export default class TagRenderingQuestion extends Combine {
configuration: TagRenderingConfig, configuration: TagRenderingConfig,
applicableMappings: { if: TagsFilter; ifnot?: TagsFilter, then: TypedTranslation<object>; icon?: string; iconClass?: string, addExtraTags: Tag[], searchTerms?: Record<string, string[]> }[], tagsSource: UIEventSource<any>): InputElement<TagsFilter> { applicableMappings: { if: TagsFilter; ifnot?: TagsFilter, then: TypedTranslation<object>; icon?: string; iconClass?: string, addExtraTags: Tag[], searchTerms?: Record<string, string[]> }[], tagsSource: UIEventSource<any>): InputElement<TagsFilter> {
const values: { show: BaseUIElement, value: number, mainTerm: Record<string, string>, searchTerms?: Record<string, string[]> }[] = [] const values: { show: BaseUIElement, value: number, mainTerm: Record<string, string>, searchTerms?: Record<string, string[]> }[] = []
const addIcons = applicableMappings.some(m => m.icon !== undefined)
for (let i = 0; i < applicableMappings.length; i++) { for (let i = 0; i < applicableMappings.length; i++) {
const mapping = applicableMappings[i]; const mapping = applicableMappings[i];
const tr = mapping.then.Subs(tagsSource.data) const tr = mapping.then.Subs(tagsSource.data)
const patchedMapping = <{ iconClass: "small-height", then: TypedTranslation<object> }>{ const patchedMapping = <{ iconClass: "small-height", then: TypedTranslation<object> }>{
...mapping, ...mapping,
iconClass: `small-height`, iconClass: `small-height`,
icon: mapping.icon ?? "./assets/svg/none.svg" icon: mapping.icon ?? (addIcons ? "./assets/svg/none.svg": undefined)
} }
const fancy = TagRenderingQuestion.GenerateMappingContent(patchedMapping, tagsSource, state).SetClass("normal-background") const fancy = TagRenderingQuestion.GenerateMappingContent(patchedMapping, tagsSource, state).SetClass("normal-background")
values.push({ values.push({

10
Utils/LanguageUtils.ts Normal file
View file

@ -0,0 +1,10 @@
import * as used_languages from "../assets/generated/used_languages.json"
export default class LanguageUtils {
/**
* All the languages there is currently language support for in MapComplete
*/
public static readonly usedLanguages : Set<string> = new Set(used_languages.languages)
}

39
Utils/WikidataUtils.ts Normal file
View file

@ -0,0 +1,39 @@
export default class WikidataUtils {
/**
* Mapping from wikidata-codes to weblate-codes. The wikidata-code is the key, mapcomplete/weblate is the value
*/
public static readonly languageRemapping = {
"nb":"nb_NO",
"zh-hant":"zh_Hant",
"zh-hans":"zh_Hans",
"pt-br":"pt_BR"
}
/**
* Extract languages and their language in every language from the data source.
* The returned mapping will be {languageCode --> {languageCode0 --> language as written in languageCode0 } }
* @param data
* @param remapLanguages
*/
public static extractLanguageData(data: {lang: {value:string}, code: {value: string}, label: {value: string}} [], remapLanguages: Record<string, string>): Map<string, Map<string, string>>{
console.log("Got "+data.length+" entries")
const perId = new Map<string, Map<string, string>>();
for (const element of data) {
let id = element.code.value
id = remapLanguages[id] ?? id
let labelLang = element.label["xml:lang"]
labelLang = remapLanguages[labelLang] ?? labelLang
const value = element.label.value
if(!perId.has(id)){
perId.set(id, new Map<string, string>())
}
perId.get(id).set(labelLang, value)
}
console.log("Got "+perId.size+" languages")
return perId
}
}

View file

@ -304,76 +304,25 @@
"phone", "phone",
"email", "email",
{ {
"id": "language", "builtin": "wikidata.school-language",
"override": {
"+mappings": [
{
"if": "school:language=",
"hideInAnswer": true,
"then": {
"en": "The main language of this school is unknown",
"nl": "De voertaal van deze school is niet gekend"
}
}
],
"question": { "question": {
"en": "What is the main language of this school?<div class='subtle'>What language is spoken with the students in non-language related courses and with the administration?</div>", "en": "What is the main language of this school?<div class='subtle'>What language is spoken with the students in non-language related courses and with the administration?</div>",
"nl": "Wat is de voertaal van deze school?<div class='subtle'>Welke taal wordt met de studenten gesproken in niet-taal-gerelateerde vakken en met de administratie?</div>", "nl": "Wat is de voertaal van deze school?<div class='subtle'>Welke taal wordt met de studenten gesproken in niet-taal-gerelateerde vakken en met de administratie?</div>",
"de": "Was ist die Hauptsprache dieser Schule?<div class='subtle'>Welche Sprache wird mit den Schülern in den nicht sprachbezogenen Kursen und mit der Verwaltung gesprochen?</div>", "de": "Was ist die Hauptsprache dieser Schule?<div class='subtle'>Welche Sprache wird mit den Schülern in den nicht sprachbezogenen Kursen und mit der Verwaltung gesprochen?</div>",
"fr": "Quelle est la langue principale de cette école ?<div class='subtle'>Quelle langue est parlée avec les élèves des cours non linguistiques et avec l'administration ?</div>" "fr": "Quelle est la langue principale de cette école ?<div class='subtle'>Quelle langue est parlée avec les élèves des cours non linguistiques et avec l'administration ?</div>"
},
"render": {
"en": "{school:language} is the main language of {title()}",
"nl": "{school:language} is de voertaal van {title()}",
"de": "{school:language} ist die Hauptsprache von {title()}",
"fr": "{school:language} est la langue principale de {title()}"
},
"freeform": {
"key": "school:language",
"inline": true,
"placeholder": {
"en": "Language in lowercase English",
"nl": "Taal in lowercase Engel",
"de": "Sprache in Englisch in Kleinbuchstaben"
},
"addExtraTags": [
"fixme=Freeform tag `school:language` used, to be doublechecked"
]
},
"mappings": [
{
"if": "school:language=english",
"then": {
"en": "The main language of this school is unknown",
"nl": "De voertaal van deze school is niet gekend",
"de": "Die Hauptsprache dieser Schule ist unbekannt",
"fr": "La langue principale de cette école est inconnue"
} }
},
{
"if": "school:language=french",
"then": {
"en": "French is the main language of {name}",
"nl": "Frans is de voertaal van {name}",
"de": "Französisch ist die Hauptsprache von {name}"
} }
},
{
"if": "school:language=dutch",
"then": {
"en": "Dutch is the main language of {name}",
"nl": "Nederlands is de voertaal van {name}",
"de": "Niederländisch ist die Hauptsprache von {name}"
}
},
{
"if": "school:language=german",
"then": {
"en": "German is the main language of {name}",
"nl": "Duits is de voertaal van {name}",
"de": "Deutsch ist die Hauptsprache von {name}"
}
},
{
"if": "school:language=",
"then": {
"en": "The main language of this school is unknown",
"nl": "De voertaal van deze school is niet gekend",
"de": "Die Hauptsprache dieser Schule ist unbekannt",
"fr": "La langue principale de cette école est inconnue"
},
"hideInAnswer": true
}
]
} }
], ],
"presets": [ "presets": [

View file

@ -36,7 +36,7 @@
"generate:schemas": "ts2json-schema -p Models/ThemeConfig/Json/ -o Docs/Schemas/ -t tsconfig.json -R . -m \".*ConfigJson\" && ts-node scripts/fixSchemas.ts ", "generate:schemas": "ts2json-schema -p Models/ThemeConfig/Json/ -o Docs/Schemas/ -t tsconfig.json -R . -m \".*ConfigJson\" && ts-node scripts/fixSchemas.ts ",
"generate:service-worker": "tsc service-worker.ts && git_hash=$(git rev-parse HEAD) && sed -i \"s/GITHUB-COMMIT/$git_hash/\" service-worker.js", "generate:service-worker": "tsc service-worker.ts && git_hash=$(git rev-parse HEAD) && sed -i \"s/GITHUB-COMMIT/$git_hash/\" service-worker.js",
"optimize-images": "cd assets/generated/ && find -name '*.png' -exec optipng '{}' \\; && echo 'PNGs are optimized'", "optimize-images": "cd assets/generated/ && find -name '*.png' -exec optipng '{}' \\; && echo 'PNGs are optimized'",
"reset:layeroverview": "echo {\\\"layers\\\":[], \\\"themes\\\":[]} > ./assets/generated/known_layers_and_themes.json && echo {\\\"layers\\\": []} > ./assets/generated/known_layers.json && rm ./asssets/generated/layers/* && rm ./assets/generated/themes/*", "reset:layeroverview": "echo {\\\"layers\\\":[], \\\"themes\\\":[]} > ./assets/generated/known_layers_and_themes.json && echo {\\\"layers\\\": []} > ./assets/generated/known_layers.json && rm ./assets/generated/layers/*.json && rm ./assets/generated/themes/*.json",
"generate": "mkdir -p ./assets/generated; npm run reset:layeroverview; npm run generate:images; npm run generate:charging-stations; npm run generate:translations; npm run generate:licenses; npm run generate:layeroverview; npm run generate:service-worker", "generate": "mkdir -p ./assets/generated; npm run reset:layeroverview; npm run generate:images; npm run generate:charging-stations; npm run generate:translations; npm run generate:licenses; npm run generate:layeroverview; npm run generate:service-worker",
"generate:charging-stations": "cd ./assets/layers/charging_station && ts-node csvToJson.ts && cd -", "generate:charging-stations": "cd ./assets/layers/charging_station && ts-node csvToJson.ts && cd -",
"prepare-deploy": "npm run generate:service-worker && ./scripts/build.sh", "prepare-deploy": "npm run generate:service-worker && ./scripts/build.sh",

View file

@ -6,19 +6,10 @@ import * as wds from "wikidata-sdk"
import {Utils} from "../Utils"; import {Utils} from "../Utils";
import ScriptUtils from "./ScriptUtils"; import ScriptUtils from "./ScriptUtils";
import {existsSync, readFileSync, writeFileSync} from "fs"; import {existsSync, readFileSync, writeFileSync} from "fs";
import * as used_languages from "../assets/generated/used_languages.json"
import {QuestionableTagRenderingConfigJson} from "../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"; import {QuestionableTagRenderingConfigJson} from "../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson";
import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson"; import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson";
import WikidataUtils from "../Utils/WikidataUtils";
const languageRemap = { import LanguageUtils from "../Utils/LanguageUtils";
// MapComplete (or weblate) on the left, language of wikimedia on the right
"nb":"nb_NO",
"zh-hant":"zh_Hant",
"zh-hans":"zh_Hans",
"pt-br":"pt_BR"
}
const usedLanguages : Set<string> = new Set(used_languages.languages)
async function fetch(target: string){ async function fetch(target: string){
const regular = await fetchRegularLanguages() const regular = await fetchRegularLanguages()
@ -75,32 +66,13 @@ async function fetchSpecial(id: number, code: string) {
return bindings return bindings
} }
function extract(data){
console.log("Got "+data.length+" entries")
const perId = new Map<string, Map<string, string>>();
for (const element of data) {
let id = element.code.value
id = languageRemap[id] ?? id
let labelLang = element.label["xml:lang"]
labelLang = languageRemap[labelLang] ?? labelLang
const value = element.label.value
if(!perId.has(id)){
perId.set(id, new Map<string, string>())
}
perId.get(id).set(labelLang, value)
}
console.log("Got "+perId.size+" languages")
return perId
}
function getNativeList(langs: Map<string, Map<string, string>>){ function getNativeList(langs: Map<string, Map<string, string>>){
const native = {} const native = {}
const keys: string[] = Array.from(langs.keys()) const keys: string[] = Array.from(langs.keys())
keys.sort() keys.sort()
for (const key of keys) { for (const key of keys) {
const translations: Map<string, string> = langs.get(key) const translations: Map<string, string> = langs.get(key)
if(!usedLanguages.has(key)){ if(!LanguageUtils.usedLanguages.has(key)){
continue continue
} }
native[key] = translations.get(key) native[key] = translations.get(key)
@ -143,17 +115,17 @@ async function main(wipeCache = false){
console.log("Reusing the cached file") console.log("Reusing the cached file")
} }
const data = JSON.parse(readFileSync( cacheFile, "UTF8")) const data = JSON.parse(readFileSync( cacheFile, "UTF8"))
const perId = extract(data) const perId = WikidataUtils.extractLanguageData(data, WikidataUtils.languageRemapping)
const nativeList = getNativeList(perId) const nativeList = getNativeList(perId)
writeFileSync("./assets/language_native.json", JSON.stringify(nativeList, null, " ")) writeFileSync("./assets/language_native.json", JSON.stringify(nativeList, null, " "))
const translations = Utils.MapToObj(perId, (value, key) => { const translations = Utils.MapToObj(perId, (value, key) => {
if(!usedLanguages.has(key)){ if(!LanguageUtils.usedLanguages.has(key)){
return undefined // Remove unused languages return undefined // Remove unused languages
} }
return Utils.MapToObj(value, (v, k ) => { return Utils.MapToObj(value, (v, k ) => {
if(!usedLanguages.has(k)){ if(!LanguageUtils.usedLanguages.has(k)){
return undefined return undefined
} }
return v return v

View file

@ -20,6 +20,7 @@ import {PrepareLayer} from "../Models/ThemeConfig/Conversion/PrepareLayer";
import {PrepareTheme} from "../Models/ThemeConfig/Conversion/PrepareTheme"; import {PrepareTheme} from "../Models/ThemeConfig/Conversion/PrepareTheme";
import {DesugaringContext} from "../Models/ThemeConfig/Conversion/Conversion"; import {DesugaringContext} from "../Models/ThemeConfig/Conversion/Conversion";
import {Utils} from "../Utils"; import {Utils} from "../Utils";
import {AllKnownLayouts} from "../Customizations/AllKnownLayouts";
// This scripts scans 'assets/layers/*.json' for layer definition files and 'assets/themes/*.json' for theme definition files. // This scripts scans 'assets/layers/*.json' for layer definition files and 'assets/themes/*.json' for theme definition files.
// It spits out an overview of those to be used to load them // It spits out an overview of those to be used to load them
@ -216,7 +217,7 @@ class LayerOverviewUtils {
writeFileSync("./assets/generated/known_layers.json", JSON.stringify({layers: Array.from(sharedLayers.values())})) writeFileSync("./assets/generated/known_layers.json", JSON.stringify({layers: Array.from(sharedLayers.values())}))
if (recompiledThemes.length > 0) { if (recompiledThemes.length > 0 && !(recompiledThemes.length === 1 && recompiledThemes[0] === "mapcomplate-changes")) {
// mapcomplete-changes shows an icon for each corresponding mapcomplete-theme // mapcomplete-changes shows an icon for each corresponding mapcomplete-theme
const iconsPerTheme = const iconsPerTheme =
Array.from(sharedThemes.values()).map(th => ({ Array.from(sharedThemes.values()).map(th => ({
@ -232,6 +233,10 @@ class LayerOverviewUtils {
this.checkAllSvgs() this.checkAllSvgs()
if(AllKnownLayouts.getSharedLayersConfigs().size == 0){
throw "This was a bootstrapping-run. Run generate layeroverview again!"
}
const green = s => '\x1b[92m' + s + '\x1b[0m' const green = s => '\x1b[92m' + s + '\x1b[0m'
console.log(green("All done!")) console.log(green("All done!"))
} }
@ -242,11 +247,11 @@ class LayerOverviewUtils {
console.log(" ---------- VALIDATING BUILTIN LAYERS ---------") console.log(" ---------- VALIDATING BUILTIN LAYERS ---------")
const sharedTagRenderings = this.getSharedTagRenderings(doesImageExist); const sharedTagRenderings = this.getSharedTagRenderings(doesImageExist);
const sharedLayers = new Map<string, LayerConfigJson>()
const state: DesugaringContext = { const state: DesugaringContext = {
tagRenderings: sharedTagRenderings, tagRenderings: sharedTagRenderings,
sharedLayers sharedLayers: AllKnownLayouts.getSharedLayersConfigs()
} }
const sharedLayers = new Map<string, LayerConfigJson>()
const prepLayer = new PrepareLayer(state); const prepLayer = new PrepareLayer(state);
const skippedLayers: string[] = [] const skippedLayers: string[] = []
const recompiledLayers: string[] = [] const recompiledLayers: string[] = []
@ -258,6 +263,7 @@ class LayerOverviewUtils {
const sharedLayer = JSON.parse(readFileSync(targetPath, "utf8")) const sharedLayer = JSON.parse(readFileSync(targetPath, "utf8"))
sharedLayers.set(sharedLayer.id, sharedLayer) sharedLayers.set(sharedLayer.id, sharedLayer)
skippedLayers.push(sharedLayer.id) skippedLayers.push(sharedLayer.id)
console.log("Loaded "+sharedLayer.id)
continue; continue;
} }

View file

@ -1,16 +1,12 @@
/*** /***
* Parses presets from the iD repository and extracts some usefull tags from them * Parses presets from the iD repository and extracts some usefull tags from them
*/ */
import ScriptUtils from "./ScriptUtils"; import ScriptUtils from "../ScriptUtils";
import {existsSync, readFileSync, writeFileSync} from "fs"; import {existsSync, readFileSync, writeFileSync} from "fs";
import * as known_languages from "../assets/language_native.json" import * as known_languages from "../../assets/language_native.json"
import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson"; import {LayerConfigJson} from "../../Models/ThemeConfig/Json/LayerConfigJson";
import { import {MappingConfigJson} from "../../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson";
MappingConfigJson, import SmallLicense from "../../Models/smallLicense";
QuestionableTagRenderingConfigJson
} from "../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson";
import SmallLicense from "../Models/smallLicense";
interface IconThief { interface IconThief {
steal(iconName: string): boolean steal(iconName: string): boolean

View file

@ -0,0 +1,86 @@
/*
* Uses the languages in and to every translation from wikidata to generate a language question in wikidata/wikidata
* */
import WikidataUtils from "../../Utils/WikidataUtils";
import {existsSync, mkdirSync, readFileSync, writeFileSync} from "fs";
import {LayerConfigJson} from "../../Models/ThemeConfig/Json/LayerConfigJson";
import {MappingConfigJson} from "../../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson";
import LanguageUtils from "../../Utils/LanguageUtils";
function main(){
const sourcepath = "assets/generated/languages-wd.json";
console.log(`Converting language data file '${sourcepath}' into a tagMapping`)
const languages = WikidataUtils.extractLanguageData(JSON.parse(readFileSync(sourcepath, "utf8")), {})
const mappings : MappingConfigJson[] = []
const schoolmappings : MappingConfigJson[] = []
languages.forEach((l, code) => {
const then : Record<string, string>= {}
l.forEach((tr, lng) => {
const languageCodeWeblate = WikidataUtils.languageRemapping[lng] ?? lng;
if(!LanguageUtils.usedLanguages.has(languageCodeWeblate)){
return;
}
then[languageCodeWeblate] = tr
})
mappings.push(<MappingConfigJson>{
if: "language:" + code + "=yes",
ifnot: "language:" + code + "=",
searchTerms: {
"*": [code]
},
then
})
schoolmappings.push(<MappingConfigJson>{
if: "school:language=" + code,
then
})
})
const wikidataLayer = <LayerConfigJson>{
id: "wikidata",
description: "Various tagrenderings which are generated from Wikidata. Automatically generated with a script, don't edit manually",
"#dont-translate": "*",
"source": {
"osmTags": "id~*"
},
"mapRendering": null,
tagRenderings: [
{
id: "language",
// @ts-ignore
description: "Enables to pick *a single* 'language:<lng>=yes' within the mappings",
mappings,
},
{
builtin: "wikidata.language",
override: {
id: "language-multi",
// @ts-ignore
description: "Enables to pick *multiple* 'language:<lng>=yes' within the mappings",
multiAnswer: true
}
},
{
id:"school-language",
// @ts-ignore
description: "Enables to pick a single 'school:language=<lng>' within the mappings",
multiAnswer: true,
mappings: schoolmappings
}
]
}
const dir = "./assets/layers/wikidata/"
if(!existsSync(dir)){
mkdirSync(dir)
}
const path = dir + "wikidata.json"
writeFileSync(path, JSON.stringify(wikidataLayer, null, " "))
console.log("Written "+path)
}
main()