forked from MapComplete/MapComplete
		
	Wikidata language picker
This commit is contained in:
		
							parent
							
								
									b75581405e
								
							
						
					
					
						commit
						325e30666b
					
				
					 14 changed files with 335 additions and 213 deletions
				
			
		|  | @ -10,6 +10,7 @@ import Constants from "../Models/Constants"; | |||
| import {Utils} from "../Utils"; | ||||
| import Link from "../UI/Base/Link"; | ||||
| import {LayoutConfigJson} from "../Models/ThemeConfig/Json/LayoutConfigJson"; | ||||
| import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson"; | ||||
| 
 | ||||
| export class AllKnownLayouts { | ||||
|     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>(); | ||||
|         for (const layer of known_themes.layers) { | ||||
|         for (const layer of known_themes["layers"]) { | ||||
|             try { | ||||
|                 // @ts-ignore
 | ||||
|                 const parsed = new LayerConfig(layer, "shared_layers") | ||||
|  | @ -226,6 +227,16 @@ export class AllKnownLayouts { | |||
|         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[] { | ||||
|         const list = [] | ||||
|         allKnownLayouts.forEach((layout) => { | ||||
|  | @ -236,7 +247,7 @@ export class AllKnownLayouts { | |||
| 
 | ||||
|     private static AllLayouts(): Map<string, LayoutConfig> { | ||||
|         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) | ||||
|             dict.set(layout.id, layout) | ||||
|             for (let i = 0; i < layout.layers.length; i++) { | ||||
|  |  | |||
|  | @ -95,9 +95,32 @@ export class AddContextToTranslations<T> extends DesugaringStep<T> { | |||
|      *   ]   | ||||
|      * } | ||||
|      * 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[] } { | ||||
| 
 | ||||
|         if(json["#dont-translate"] === "*"){ | ||||
|             return {result: json} | ||||
|         } | ||||
|          | ||||
|         const result = Utils.WalkJson(json, (leaf, path) => { | ||||
|             if(leaf === undefined || leaf === null){ | ||||
|                 return leaf | ||||
|  |  | |||
|  | @ -141,17 +141,21 @@ export class Each<X, Y> extends Conversion<X[], Y[]> { | |||
| 
 | ||||
| export class On<P, T> extends DesugaringStep<T> { | ||||
|     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})`); | ||||
|         this.step = step; | ||||
|         if(typeof step === "function"){ | ||||
|             this.step = step; | ||||
|         }else{ | ||||
|             this.step = _ => step | ||||
|         } | ||||
|         this.key = key; | ||||
|     } | ||||
| 
 | ||||
|     convert(json: T, context: string): { result: T; errors?: string[]; warnings?: string[], information?: string[] } { | ||||
|         json = {...json} | ||||
|         const step = this.step | ||||
|         const step = this.step(json) | ||||
|         const key = this.key; | ||||
|         const value: P = json[key] | ||||
|         if (value === undefined || value === null) { | ||||
|  |  | |||
|  | @ -12,10 +12,12 @@ import {AddContextToTranslations} from "./AddContextToTranslations"; | |||
| 
 | ||||
| class ExpandTagRendering extends Conversion<string | TagRenderingConfigJson | { builtin: string | string[], override: any }, TagRenderingConfigJson[]> { | ||||
|     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"); | ||||
|         this._state = state; | ||||
|         this._self = self; | ||||
|     } | ||||
| 
 | ||||
|     convert(json: string | TagRenderingConfigJson | { builtin: string | string[]; override: any }, context: string): { result: TagRenderingConfigJson[]; errors: string[]; warnings: string[] } { | ||||
|  | @ -33,42 +35,50 @@ class ExpandTagRendering extends Conversion<string | TagRenderingConfigJson | { | |||
|         if (state.tagRenderings.has(name)) { | ||||
|             return [state.tagRenderings.get(name)] | ||||
|         } | ||||
|         if (name.indexOf(".") >= 0) { | ||||
|             const spl = name.split("."); | ||||
|             const layer = state.sharedLayers.get(spl[0]) | ||||
|             if (spl.length === 2 && layer !== undefined) { | ||||
|                 const id = spl[1]; | ||||
|         if (name.indexOf(".") < 0) { | ||||
|             return undefined; | ||||
|         } | ||||
|          | ||||
|         const spl = name.split("."); | ||||
|         let layer = state.sharedLayers.get(spl[0]) | ||||
|         if (spl[0] === this._self.id) { | ||||
|             layer = this._self | ||||
|         } | ||||
| 
 | ||||
|                 const layerTrs = <TagRenderingConfigJson[]>layer.tagRenderings.filter(tr => tr["id"] !== undefined) | ||||
|                 let matchingTrs: TagRenderingConfigJson[] | ||||
|                 if (id === "*") { | ||||
|                     matchingTrs = layerTrs | ||||
|                 } else if (id.startsWith("*")) { | ||||
|                     const id_ = id.substring(1) | ||||
|                     matchingTrs = layerTrs.filter(tr => tr.group === id_ || tr.labels?.indexOf(id_) >= 0) | ||||
|                 } else { | ||||
|                     matchingTrs = layerTrs.filter(tr => tr.id === id) | ||||
|                 } | ||||
|         if (spl.length !== 2 || layer === undefined) { | ||||
|             return undefined | ||||
|         } | ||||
|          | ||||
|         const id = spl[1]; | ||||
| 
 | ||||
|         const layerTrs = <TagRenderingConfigJson[]>layer.tagRenderings.filter(tr => tr["id"] !== undefined) | ||||
|         let matchingTrs: TagRenderingConfigJson[] | ||||
|         if (id === "*") { | ||||
|             matchingTrs = layerTrs | ||||
|         } else if (id.startsWith("*")) { | ||||
|             const id_ = id.substring(1) | ||||
|             matchingTrs = layerTrs.filter(tr => tr.group === id_ || tr.labels?.indexOf(id_) >= 0) | ||||
|         } else { | ||||
|             matchingTrs = layerTrs.filter(tr => tr.id === id) | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|                 const contextWriter = new AddContextToTranslations<TagRenderingConfigJson>("layers:") | ||||
|                 for (let i = 0; i < matchingTrs.length; i++) { | ||||
|                     // The matched tagRenderings are 'stolen' from another layer. This means that they must match the layer condition before being shown
 | ||||
|                     let found : TagRenderingConfigJson = Utils.Clone(matchingTrs[i]); | ||||
|                     if (found.condition === undefined) { | ||||
|                         found.condition = layer.source.osmTags | ||||
|                     } else { | ||||
|                         found.condition = {and: [found.condition, layer.source.osmTags]} | ||||
|                     } | ||||
|                      | ||||
|                     found = contextWriter.convertStrict(found, layer.id+ ".tagRenderings."+found["id"]) | ||||
|                     matchingTrs[i] = found | ||||
|                 } | ||||
| 
 | ||||
|                 if (matchingTrs.length !== 0) { | ||||
|                     return matchingTrs | ||||
|                 } | ||||
|         const contextWriter = new AddContextToTranslations<TagRenderingConfigJson>("layers:") | ||||
|         for (let i = 0; i < matchingTrs.length; i++) { | ||||
|             // The matched tagRenderings are 'stolen' from another layer. This means that they must match the layer condition before being shown
 | ||||
|             let found: TagRenderingConfigJson = Utils.Clone(matchingTrs[i]); | ||||
|             if (found.condition === undefined) { | ||||
|                 found.condition = layer.source.osmTags | ||||
|             } else { | ||||
|                 found.condition = {and: [found.condition, layer.source.osmTags]} | ||||
|             } | ||||
| 
 | ||||
|             found = contextWriter.convertStrict(found, layer.id + ".tagRenderings." + found["id"]) | ||||
|             matchingTrs[i] = found | ||||
|         } | ||||
| 
 | ||||
|         if (matchingTrs.length !== 0) { | ||||
|             return matchingTrs | ||||
|         } | ||||
|         return undefined; | ||||
|     } | ||||
|  | @ -86,7 +96,7 @@ class ExpandTagRendering extends Conversion<string | TagRenderingConfigJson | { | |||
|             const lookup = this.lookup(tr); | ||||
|             if (lookup === undefined) { | ||||
|                 const isTagRendering = ctx.indexOf("On(mapRendering") < 0 | ||||
|                 if(isTagRendering){ | ||||
|                 if (isTagRendering) { | ||||
|                     warnings.push(ctx + "A literal rendering was detected: " + tr) | ||||
|                 } | ||||
|                 return [{ | ||||
|  | @ -114,13 +124,26 @@ class ExpandTagRendering extends Conversion<string | TagRenderingConfigJson | { | |||
|             for (const name of names) { | ||||
|                 const lookup = this.lookup(name) | ||||
|                 if (lookup === undefined) { | ||||
|                     let candidates =  Array.from(state.tagRenderings.keys()) | ||||
|                     if(name.indexOf(".") > 0){ | ||||
|                         const [layer, search] = name.split(".") | ||||
|                         candidates = Utils.NoNull( state.sharedLayers.get(layer).tagRenderings.map(tr => tr["id"])).map(id => layer+"."+id) | ||||
|                     let candidates = Array.from(state.tagRenderings.keys()) | ||||
|                     if (name.indexOf(".") > 0) { | ||||
|                         const [layerName, search] = name.split(".") | ||||
|                         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); | ||||
|                     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(", ") + "?") | ||||
|                     continue | ||||
|                 } | ||||
|                 for (let foundTr of lookup) { | ||||
|  | @ -168,7 +191,7 @@ export class ExpandRewrite<T> extends Conversion<T | RewritableConfigJson<T>, T[ | |||
|      *   "someKey": "somevalue {xyz}" | ||||
|      * } | ||||
|      * ExpandRewrite.RewriteParts("{xyz}", "rewritten", spec) // => {"someKey": "somevalue rewritten"}
 | ||||
|      *  | ||||
|      * | ||||
|      * // should substitute all occurances in strings
 | ||||
|      * const spec = { | ||||
|      *   "someKey": "The left|right side has {key:left|right}" | ||||
|  | @ -187,8 +210,8 @@ export class ExpandRewrite<T> extends Conversion<T | RewritableConfigJson<T>, T[ | |||
| 
 | ||||
|             if (typeof obj === "string") { | ||||
|                 // This is a simple string - we do a simple replace
 | ||||
|                 while(obj.indexOf(keyToRewrite) >= 0){ | ||||
|                    obj = obj.replace(keyToRewrite, target) | ||||
|                 while (obj.indexOf(keyToRewrite) >= 0) { | ||||
|                     obj = obj.replace(keyToRewrite, target) | ||||
|                 } | ||||
|                 return obj | ||||
|             } | ||||
|  | @ -199,17 +222,17 @@ export class ExpandRewrite<T> extends Conversion<T | RewritableConfigJson<T>, T[ | |||
| 
 | ||||
|             if (typeof obj === "object") { | ||||
|                 obj = {...obj} | ||||
|                  | ||||
| 
 | ||||
|                 const isTr = targetIsTranslation && Translations.isProbablyATranslation(obj) | ||||
|                  | ||||
| 
 | ||||
|                 for (const key in obj) { | ||||
|                     let subtarget = target | ||||
|                     if(isTr && target[key] !== undefined){ | ||||
|                     if (isTr && target[key] !== undefined) { | ||||
|                         // The target is a translation AND the current object is a translation
 | ||||
|                         // This means we should recursively replace with the translated value
 | ||||
|                         subtarget = target[key] | ||||
|                     } | ||||
|                      | ||||
| 
 | ||||
|                     obj[key] = replaceRecursive(obj[key], subtarget) | ||||
|                 } | ||||
|                 return obj | ||||
|  | @ -233,7 +256,7 @@ export class ExpandRewrite<T> extends Conversion<T | RewritableConfigJson<T>, T[ | |||
|      *     renderings: "The value of xyz is abc" | ||||
|      * } | ||||
|      * new ExpandRewrite().convertStrict(spec, "test") // => ["The value of X is A", "The value of Y is B", "The value of Z is C"]
 | ||||
|      *  | ||||
|      * | ||||
|      * // should rewrite with translations
 | ||||
|      * const spec = <RewritableConfigJson<any>>{ | ||||
|      *     rewrite: { | ||||
|  | @ -287,9 +310,9 @@ export class ExpandRewrite<T> extends Conversion<T | RewritableConfigJson<T>, T[ | |||
|         {// sanity check: {rewrite: ["a", "b"] should have the right amount of 'intos' in every case
 | ||||
|             for (let i = 0; i < rewrite.rewrite.into.length; i++) { | ||||
|                 const into = keysToRewrite.into[i] | ||||
|                 if(into.length !== rewrite.rewrite.sourceString.length){ | ||||
|                 throw `${context}.into.${i} Error in rewrite: there are ${rewrite.rewrite.sourceString.length} keys to rewrite, but entry ${i} has only ${into.length} values` | ||||
|                      | ||||
|                 if (into.length !== rewrite.rewrite.sourceString.length) { | ||||
|                     throw `${context}.into.${i} Error in rewrite: there are ${rewrite.rewrite.sourceString.length} keys to rewrite, but entry ${i} has only ${into.length} values` | ||||
| 
 | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | @ -315,50 +338,50 @@ export class ExpandRewrite<T> extends Conversion<T | RewritableConfigJson<T>, T[ | |||
|  */ | ||||
| export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> { | ||||
|     constructor() { | ||||
|         super("Converts a 'special' translation into a regular translation which uses parameters", ["special"],"RewriteSpecial"); | ||||
|         super("Converts a 'special' translation into a regular translation which uses parameters", ["special"], "RewriteSpecial"); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Does the heavy lifting and conversion | ||||
|      *  | ||||
|      * | ||||
|      * // should not do anything if no 'special'-key is present
 | ||||
|      * RewriteSpecial.convertIfNeeded({"en": "xyz", "nl": "abc"}, [], "test") // => {"en": "xyz", "nl": "abc"}
 | ||||
|      *  | ||||
|      * | ||||
|      * // should handle a simple special case
 | ||||
|      * RewriteSpecial.convertIfNeeded({"special": {"type":"image_carousel"}}, [], "test") // => {'*': "{image_carousel()}"}
 | ||||
|      *  | ||||
|      * | ||||
|      * // should handle special case with a parameter
 | ||||
|      * RewriteSpecial.convertIfNeeded({"special": {"type":"image_carousel", "image_key": "some_image_key"}}, [], "test") // =>  {'*': "{image_carousel(some_image_key)}"}
 | ||||
|      *  | ||||
|      * | ||||
|      * // should handle special case with a translated parameter
 | ||||
|      * const spec = {"special": {"type":"image_upload", "label": {"en": "Add a picture to this object", "nl": "Voeg een afbeelding toe"}}} | ||||
|      * const r = RewriteSpecial.convertIfNeeded(spec, [], "test") | ||||
|      * r // => {"en": "{image_upload(,Add a picture to this object)}", "nl": "{image_upload(,Voeg een afbeelding toe)}" }
 | ||||
|      *  | ||||
|      * | ||||
|      * // should handle special case with a prefix and postfix
 | ||||
|      * const spec = {"special": {"type":"image_upload" }, before: {"en": "PREFIX "}, after: {"en": " POSTFIX", nl: " Achtervoegsel"} } | ||||
|      * const r = RewriteSpecial.convertIfNeeded(spec, [], "test") | ||||
|      * r // => {"en": "PREFIX {image_upload(,)} POSTFIX", "nl": "PREFIX {image_upload(,)} Achtervoegsel" }
 | ||||
|      *  | ||||
|      * | ||||
|      * // should warn for unexpected keys
 | ||||
|      * const errors = [] | ||||
|      * RewriteSpecial.convertIfNeeded({"special": {type: "image_carousel"}, "en": "xyz"}, errors, "test") // =>  {'*': "{image_carousel()}"}
 | ||||
|      * errors // => ["At test: Unexpected key in a special block: en"]
 | ||||
|      *  | ||||
|      * | ||||
|      * // should give an error on unknown visualisations
 | ||||
|      * const errors = [] | ||||
|      * RewriteSpecial.convertIfNeeded({"special": {type: "qsdf"}}, errors, "test") // => undefined
 | ||||
|      * errors.length // => 1
 | ||||
|      * errors[0].indexOf("Special visualisation 'qsdf' not found") >= 0 // => true
 | ||||
|      *  | ||||
|      * | ||||
|      * // should give an error is 'type' is missing
 | ||||
|      * const errors = [] | ||||
|      * RewriteSpecial.convertIfNeeded({"special": {}}, errors, "test") // => undefined
 | ||||
|      * errors // => ["A 'special'-block should define 'type' to indicate which visualisation should be used"]
 | ||||
|      */ | ||||
|     private static convertIfNeeded(input: (object & {special : {type: string}}) | any, errors: string[], context: string): any { | ||||
|     private static convertIfNeeded(input: (object & { special: { type: string } }) | any, errors: string[], context: string): any { | ||||
|         const special = input["special"] | ||||
|         if(special === undefined){ | ||||
|         if (special === undefined) { | ||||
|             return input | ||||
|         } | ||||
| 
 | ||||
|  | @ -367,17 +390,17 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> { | |||
|         } | ||||
| 
 | ||||
|         const type = special["type"] | ||||
|         if(type === undefined){ | ||||
|         if (type === undefined) { | ||||
|             errors.push("A 'special'-block should define 'type' to indicate which visualisation should be used") | ||||
|             return undefined | ||||
|         } | ||||
|         const vis = SpecialVisualizations.specialVisualizations.find(sp => sp.funcName === type) | ||||
|         if(vis === undefined){ | ||||
|         if (vis === undefined) { | ||||
|             const options = Utils.sortedByLevenshteinDistance(type, SpecialVisualizations.specialVisualizations, sp => sp.funcName) | ||||
|             errors.push(`Special visualisation '${type}' not found. Did you perhaps mean ${options[0].funcName}, ${options[1].funcName} or ${options[2].funcName}?\n\tFor all known special visualisations, please see https://github.com/pietervdvn/MapComplete/blob/develop/Docs/SpecialRenderings.md`) | ||||
|             return undefined | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         const argNamesList = vis.args.map(a => a.name) | ||||
|         const argNames = new Set<string>(argNamesList) | ||||
|         // Check for obsolete and misspelled arguments
 | ||||
|  | @ -385,21 +408,21 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> { | |||
|             .filter(k => !argNames.has(k)) | ||||
|             .filter(k => k !== "type") | ||||
|             .map(wrongArg => { | ||||
|             const byDistance = Utils.sortedByLevenshteinDistance(wrongArg, argNamesList, x => x) | ||||
|             return `Unexpected argument with name '${wrongArg}'. Did you mean ${byDistance[0]}?\n\tAll known arguments are ${ argNamesList.join(", ")}` ; | ||||
|         })) | ||||
|          | ||||
|                 const byDistance = Utils.sortedByLevenshteinDistance(wrongArg, argNamesList, x => x) | ||||
|                 return `Unexpected argument with name '${wrongArg}'. Did you mean ${byDistance[0]}?\n\tAll known arguments are ${argNamesList.join(", ")}`; | ||||
|             })) | ||||
| 
 | ||||
|         // Check that all obligated arguments are present. They are obligated if they don't have a preset value
 | ||||
|         for (const arg of vis.args) { | ||||
|             if (arg.required !== true) { | ||||
|                 continue; | ||||
|             } | ||||
|             const param = special[arg.name] | ||||
|             if(param === undefined){ | ||||
|             if (param === undefined) { | ||||
|                 errors.push(`Obligated parameter '${arg.name}' not found`) | ||||
|             } | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         const foundLanguages = new Set<string>() | ||||
|         const translatedArgs = argNamesList.map(nm => special[nm]) | ||||
|             .filter(v => v !== undefined) | ||||
|  | @ -407,25 +430,26 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> { | |||
|         for (const translatedArg of translatedArgs) { | ||||
|             for (const ln of Object.keys(translatedArg)) { | ||||
|                 foundLanguages.add(ln) | ||||
|             }   | ||||
|             } | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         const before = Translations.T(input.before) | ||||
|         const after = Translations.T(input.after) | ||||
| 
 | ||||
|         for (const ln of Object.keys(before?.translations??{})) { | ||||
|         for (const ln of Object.keys(before?.translations ?? {})) { | ||||
|             foundLanguages.add(ln) | ||||
|         } | ||||
|         for (const ln of Object.keys(after?.translations??{})) { | ||||
|         for (const ln of Object.keys(after?.translations ?? {})) { | ||||
|             foundLanguages.add(ln) | ||||
|         } | ||||
| 
 | ||||
|         if(foundLanguages.size === 0){ | ||||
|            const args=   argNamesList.map(nm => special[nm] ?? "").join(",") | ||||
|             return {'*': `{${type}(${args})}` | ||||
|         if (foundLanguages.size === 0) { | ||||
|             const args = argNamesList.map(nm => special[nm] ?? "").join(",") | ||||
|             return { | ||||
|                 '*': `{${type}(${args})}` | ||||
|             } | ||||
|         } | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         const result = {} | ||||
|         const languages = Array.from(foundLanguages) | ||||
|         languages.sort() | ||||
|  | @ -433,9 +457,9 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> { | |||
|             const args = [] | ||||
|             for (const argName of argNamesList) { | ||||
|                 const v = special[argName] ?? "" | ||||
|                 if(Translations.isProbablyATranslation(v)){ | ||||
|                 if (Translations.isProbablyATranslation(v)) { | ||||
|                     args.push(new Translation(v).textFor(ln)) | ||||
|                 }else{ | ||||
|                 } else { | ||||
|                     args.push(v) | ||||
|                 } | ||||
|             } | ||||
|  | @ -459,7 +483,7 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> { | |||
|      * const result = new RewriteSpecial().convert(tr,"test").result | ||||
|      * const expected = {render:  {'*': "{image_carousel(image)}"}, mappings: [{if: "other_image_key", then:  {'*': "{image_carousel(other_image_key)}"}} ]} | ||||
|      * result // => expected
 | ||||
|      *  | ||||
|      * | ||||
|      * const tr = { | ||||
|      *     render: {special: {type: "image_carousel", image_key: "image"}, before: {en: "Some introduction"} }, | ||||
|      * } | ||||
|  | @ -470,20 +494,20 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> { | |||
|     convert(json: TagRenderingConfigJson, context: string): { result: TagRenderingConfigJson; errors?: string[]; warnings?: string[]; information?: string[] } { | ||||
|         const errors = [] | ||||
|         json = Utils.Clone(json) | ||||
|         const paths : {path: string[], type?: any, typeHint?: string}[] = tagrenderingconfigmeta["default"] ?? tagrenderingconfigmeta | ||||
|         const paths: { path: string[], type?: any, typeHint?: string }[] = tagrenderingconfigmeta["default"] ?? tagrenderingconfigmeta | ||||
|         for (const path of paths) { | ||||
|             if(path.typeHint !== "rendered"){ | ||||
|             if (path.typeHint !== "rendered") { | ||||
|                 continue | ||||
|             } | ||||
|             Utils.WalkPath(path.path, json, ((leaf, travelled) => RewriteSpecial.convertIfNeeded(leaf, errors, travelled.join(".")))) | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         return { | ||||
|             result:json, | ||||
|             result: json, | ||||
|             errors | ||||
|         }; | ||||
|     } | ||||
|      | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class PrepareLayer extends Fuse<LayerConfigJson> { | ||||
|  | @ -492,11 +516,11 @@ export class PrepareLayer extends Fuse<LayerConfigJson> { | |||
|             "Fully prepares and expands a layer for the LayerConfig.", | ||||
|             new On("tagRenderings", new Each(new RewriteSpecial())), | ||||
|             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 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 On("titleIcons", new Concat(new ExpandTagRendering(state))) | ||||
|             new On("titleIcons", layer => new Concat(new ExpandTagRendering(state, layer))) | ||||
|         ); | ||||
|     } | ||||
| } | ||||
|  | @ -508,6 +508,7 @@ export class ValidateLayer extends DesugaringStep<LayerConfigJson> { | |||
|         const errors = [] | ||||
|         const warnings = [] | ||||
|         const information = [] | ||||
|         context = "While validating a layer: "+context | ||||
|         if (typeof json === "string") { | ||||
|             errors.push(context + ": This layer hasn't been expanded: " + json) | ||||
|             return { | ||||
|  |  | |||
|  | @ -236,13 +236,14 @@ export default class TagRenderingQuestion extends Combine { | |||
|         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> { | ||||
|         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++) { | ||||
|             const mapping = applicableMappings[i]; | ||||
|             const tr = mapping.then.Subs(tagsSource.data) | ||||
|             const patchedMapping = <{ iconClass: "small-height", then: TypedTranslation<object> }>{ | ||||
|                 ...mapping, | ||||
|                 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") | ||||
|             values.push({ | ||||
|  |  | |||
							
								
								
									
										10
									
								
								Utils/LanguageUtils.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Utils/LanguageUtils.ts
									
										
									
									
									
										Normal 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
									
								
							
							
						
						
									
										39
									
								
								Utils/WikidataUtils.ts
									
										
									
									
									
										Normal 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 | ||||
|     } | ||||
|      | ||||
| } | ||||
|  | @ -304,76 +304,25 @@ | |||
|     "phone", | ||||
|     "email", | ||||
|     { | ||||
|       "id": "language", | ||||
|       "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>", | ||||
|         "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>", | ||||
|         "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" | ||||
|       "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" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           "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 | ||||
|         ], | ||||
|         "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>", | ||||
|           "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>", | ||||
|           "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>" | ||||
|         } | ||||
|       ] | ||||
|       } | ||||
|     } | ||||
|   ], | ||||
|   "presets": [ | ||||
|  |  | |||
|  | @ -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: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'", | ||||
|     "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:charging-stations": "cd ./assets/layers/charging_station && ts-node csvToJson.ts && cd -", | ||||
|     "prepare-deploy": "npm run generate:service-worker && ./scripts/build.sh", | ||||
|  |  | |||
|  | @ -6,19 +6,10 @@ import * as wds from "wikidata-sdk" | |||
| import {Utils} from "../Utils"; | ||||
| import ScriptUtils from "./ScriptUtils"; | ||||
| import {existsSync, readFileSync, writeFileSync} from "fs"; | ||||
| import * as used_languages from "../assets/generated/used_languages.json" | ||||
| import {QuestionableTagRenderingConfigJson} from "../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"; | ||||
| import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson"; | ||||
| 
 | ||||
| const languageRemap = { | ||||
|     // 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) | ||||
| import WikidataUtils from "../Utils/WikidataUtils"; | ||||
| import LanguageUtils from "../Utils/LanguageUtils"; | ||||
| 
 | ||||
| async function fetch(target: string){ | ||||
|     const regular = await fetchRegularLanguages() | ||||
|  | @ -75,32 +66,13 @@ async function fetchSpecial(id: number, code: string) { | |||
|     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>>){ | ||||
|     const native = {} | ||||
|     const keys: string[] = Array.from(langs.keys()) | ||||
|     keys.sort() | ||||
|     for (const key of keys) { | ||||
|         const translations: Map<string, string> = langs.get(key) | ||||
|         if(!usedLanguages.has(key)){ | ||||
|         if(!LanguageUtils.usedLanguages.has(key)){ | ||||
|             continue | ||||
|         } | ||||
|         native[key] = translations.get(key) | ||||
|  | @ -143,17 +115,17 @@ async function main(wipeCache = false){ | |||
|         console.log("Reusing the cached file") | ||||
|     } | ||||
|     const data = JSON.parse(readFileSync( cacheFile, "UTF8")) | ||||
|     const perId = extract(data) | ||||
|     const perId = WikidataUtils.extractLanguageData(data, WikidataUtils.languageRemapping) | ||||
|     const nativeList = getNativeList(perId) | ||||
|     writeFileSync("./assets/language_native.json", JSON.stringify(nativeList, null, "  ")) | ||||
|      | ||||
| 
 | ||||
|     const translations = Utils.MapToObj(perId, (value, key) => { | ||||
|         if(!usedLanguages.has(key)){ | ||||
|         if(!LanguageUtils.usedLanguages.has(key)){ | ||||
|             return undefined // Remove unused languages
 | ||||
|         } | ||||
|         return Utils.MapToObj(value, (v, k ) => { | ||||
|             if(!usedLanguages.has(k)){ | ||||
|             if(!LanguageUtils.usedLanguages.has(k)){ | ||||
|                 return undefined | ||||
|             } | ||||
|             return v | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ import {PrepareLayer} from "../Models/ThemeConfig/Conversion/PrepareLayer"; | |||
| import {PrepareTheme} from "../Models/ThemeConfig/Conversion/PrepareTheme"; | ||||
| import {DesugaringContext} from "../Models/ThemeConfig/Conversion/Conversion"; | ||||
| 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.
 | ||||
| // 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())})) | ||||
| 
 | ||||
| 
 | ||||
|         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
 | ||||
|             const iconsPerTheme = | ||||
|                 Array.from(sharedThemes.values()).map(th => ({ | ||||
|  | @ -231,6 +232,10 @@ class LayerOverviewUtils { | |||
|         } | ||||
| 
 | ||||
|         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' | ||||
|         console.log(green("All done!")) | ||||
|  | @ -242,11 +247,11 @@ class LayerOverviewUtils { | |||
|         console.log("   ---------- VALIDATING BUILTIN LAYERS ---------") | ||||
| 
 | ||||
|         const sharedTagRenderings = this.getSharedTagRenderings(doesImageExist); | ||||
|         const sharedLayers = new Map<string, LayerConfigJson>() | ||||
|         const state: DesugaringContext = { | ||||
|             tagRenderings: sharedTagRenderings, | ||||
|             sharedLayers | ||||
|             sharedLayers: AllKnownLayouts.getSharedLayersConfigs() | ||||
|         } | ||||
|         const sharedLayers = new Map<string, LayerConfigJson>() | ||||
|         const prepLayer = new PrepareLayer(state); | ||||
|         const skippedLayers: string[] = [] | ||||
|         const recompiledLayers: string[] = [] | ||||
|  | @ -258,6 +263,7 @@ class LayerOverviewUtils { | |||
|                     const sharedLayer = JSON.parse(readFileSync(targetPath, "utf8")) | ||||
|                     sharedLayers.set(sharedLayer.id, sharedLayer) | ||||
|                     skippedLayers.push(sharedLayer.id) | ||||
|                     console.log("Loaded "+sharedLayer.id) | ||||
|                     continue; | ||||
|                 } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,16 +1,12 @@ | |||
| /*** | ||||
|  * 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 * as known_languages from "../assets/language_native.json" | ||||
| import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson"; | ||||
| import { | ||||
|     MappingConfigJson, | ||||
| 
 | ||||
|     QuestionableTagRenderingConfigJson | ||||
| } from "../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"; | ||||
| import SmallLicense from "../Models/smallLicense"; | ||||
| import * as known_languages from "../../assets/language_native.json" | ||||
| import {LayerConfigJson} from "../../Models/ThemeConfig/Json/LayerConfigJson"; | ||||
| import {MappingConfigJson} from "../../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"; | ||||
| import SmallLicense from "../../Models/smallLicense"; | ||||
| 
 | ||||
| interface IconThief { | ||||
|     steal(iconName: string): boolean | ||||
							
								
								
									
										86
									
								
								scripts/thieves/stealLanguages.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								scripts/thieves/stealLanguages.ts
									
										
									
									
									
										Normal 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() | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue