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 {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++) { | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|  |  | ||||||
|  | @ -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})`); | ||||||
|         this.step = step; |         if(typeof step === "function"){ | ||||||
|  |             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) { | ||||||
|  |  | ||||||
|  | @ -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,42 +35,50 @@ 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) { | ||||||
|             const spl = name.split("."); |             return undefined; | ||||||
|             const layer = state.sharedLayers.get(spl[0]) |         } | ||||||
|             if (spl.length === 2 && layer !== undefined) { |  | ||||||
|                 const id = spl[1]; |  | ||||||
|          |          | ||||||
|                 const layerTrs = <TagRenderingConfigJson[]>layer.tagRenderings.filter(tr => tr["id"] !== undefined) |         const spl = name.split("."); | ||||||
|                 let matchingTrs: TagRenderingConfigJson[] |         let layer = state.sharedLayers.get(spl[0]) | ||||||
|                 if (id === "*") { |         if (spl[0] === this._self.id) { | ||||||
|                     matchingTrs = layerTrs |             layer = this._self | ||||||
|                 } else if (id.startsWith("*")) { |         } | ||||||
|                     const id_ = id.substring(1) | 
 | ||||||
|                     matchingTrs = layerTrs.filter(tr => tr.group === id_ || tr.labels?.indexOf(id_) >= 0) |         if (spl.length !== 2 || layer === undefined) { | ||||||
|                 } else { |             return undefined | ||||||
|                     matchingTrs = layerTrs.filter(tr => tr.id === id) |         } | ||||||
|                 } |          | ||||||
|  |         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:") |         const contextWriter = new AddContextToTranslations<TagRenderingConfigJson>("layers:") | ||||||
|                 for (let i = 0; i < matchingTrs.length; i++) { |         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
 |             // 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]); |             let found: TagRenderingConfigJson = Utils.Clone(matchingTrs[i]); | ||||||
|                     if (found.condition === undefined) { |             if (found.condition === undefined) { | ||||||
|                         found.condition = layer.source.osmTags |                 found.condition = layer.source.osmTags | ||||||
|                     } else { |             } else { | ||||||
|                         found.condition = {and: [found.condition, layer.source.osmTags]} |                 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 |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|  |             found = contextWriter.convertStrict(found, layer.id + ".tagRenderings." + found["id"]) | ||||||
|  |             matchingTrs[i] = found | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (matchingTrs.length !== 0) { | ||||||
|  |             return matchingTrs | ||||||
|         } |         } | ||||||
|         return undefined; |         return undefined; | ||||||
|     } |     } | ||||||
|  | @ -86,7 +96,7 @@ class ExpandTagRendering extends Conversion<string | TagRenderingConfigJson | { | ||||||
|             const lookup = this.lookup(tr); |             const lookup = this.lookup(tr); | ||||||
|             if (lookup === undefined) { |             if (lookup === undefined) { | ||||||
|                 const isTagRendering = ctx.indexOf("On(mapRendering") < 0 |                 const isTagRendering = ctx.indexOf("On(mapRendering") < 0 | ||||||
|                 if(isTagRendering){ |                 if (isTagRendering) { | ||||||
|                     warnings.push(ctx + "A literal rendering was detected: " + tr) |                     warnings.push(ctx + "A literal rendering was detected: " + tr) | ||||||
|                 } |                 } | ||||||
|                 return [{ |                 return [{ | ||||||
|  | @ -114,13 +124,26 @@ class ExpandTagRendering extends Conversion<string | TagRenderingConfigJson | { | ||||||
|             for (const name of names) { |             for (const name of names) { | ||||||
|                 const lookup = this.lookup(name) |                 const lookup = this.lookup(name) | ||||||
|                 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(", ") + "?") | ||||||
|                     continue |                     continue | ||||||
|                 } |                 } | ||||||
|                 for (let foundTr of lookup) { |                 for (let foundTr of lookup) { | ||||||
|  | @ -187,8 +210,8 @@ export class ExpandRewrite<T> extends Conversion<T | RewritableConfigJson<T>, T[ | ||||||
| 
 | 
 | ||||||
|             if (typeof obj === "string") { |             if (typeof obj === "string") { | ||||||
|                 // This is a simple string - we do a simple replace
 |                 // This is a simple string - we do a simple replace
 | ||||||
|                 while(obj.indexOf(keyToRewrite) >= 0){ |                 while (obj.indexOf(keyToRewrite) >= 0) { | ||||||
|                    obj = obj.replace(keyToRewrite, target) |                     obj = obj.replace(keyToRewrite, target) | ||||||
|                 } |                 } | ||||||
|                 return obj |                 return obj | ||||||
|             } |             } | ||||||
|  | @ -204,7 +227,7 @@ export class ExpandRewrite<T> extends Conversion<T | RewritableConfigJson<T>, T[ | ||||||
| 
 | 
 | ||||||
|                 for (const key in obj) { |                 for (const key in obj) { | ||||||
|                     let subtarget = target |                     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
 |                         // The target is a translation AND the current object is a translation
 | ||||||
|                         // This means we should recursively replace with the translated value
 |                         // This means we should recursively replace with the translated value
 | ||||||
|                         subtarget = target[key] |                         subtarget = target[key] | ||||||
|  | @ -287,8 +310,8 @@ 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
 |         {// 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++) { |             for (let i = 0; i < rewrite.rewrite.into.length; i++) { | ||||||
|                 const into = keysToRewrite.into[i] |                 const into = keysToRewrite.into[i] | ||||||
|                 if(into.length !== rewrite.rewrite.sourceString.length){ |                 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` |                     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,7 +338,7 @@ export class ExpandRewrite<T> extends Conversion<T | RewritableConfigJson<T>, T[ | ||||||
|  */ |  */ | ||||||
| export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> { | export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> { | ||||||
|     constructor() { |     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"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | @ -356,9 +379,9 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> { | ||||||
|      * RewriteSpecial.convertIfNeeded({"special": {}}, errors, "test") // => undefined
 |      * RewriteSpecial.convertIfNeeded({"special": {}}, errors, "test") // => undefined
 | ||||||
|      * errors // => ["A 'special'-block should define 'type' to indicate which visualisation should be used"]
 |      * 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"] |         const special = input["special"] | ||||||
|         if(special === undefined){ |         if (special === undefined) { | ||||||
|             return input |             return input | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -367,12 +390,12 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const type = special["type"] |         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") |             errors.push("A 'special'-block should define 'type' to indicate which visualisation should be used") | ||||||
|             return undefined |             return undefined | ||||||
|         } |         } | ||||||
|         const vis = SpecialVisualizations.specialVisualizations.find(sp => sp.funcName === type) |         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) |             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`) |             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 |             return undefined | ||||||
|  | @ -385,9 +408,9 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> { | ||||||
|             .filter(k => !argNames.has(k)) |             .filter(k => !argNames.has(k)) | ||||||
|             .filter(k => k !== "type") |             .filter(k => k !== "type") | ||||||
|             .map(wrongArg => { |             .map(wrongArg => { | ||||||
|             const byDistance = Utils.sortedByLevenshteinDistance(wrongArg, argNamesList, x => x) |                 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(", ")}` ; |                 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
 |         // Check that all obligated arguments are present. They are obligated if they don't have a preset value
 | ||||||
|         for (const arg of vis.args) { |         for (const arg of vis.args) { | ||||||
|  | @ -395,7 +418,7 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> { | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|             const param = special[arg.name] |             const param = special[arg.name] | ||||||
|             if(param === undefined){ |             if (param === undefined) { | ||||||
|                 errors.push(`Obligated parameter '${arg.name}' not found`) |                 errors.push(`Obligated parameter '${arg.name}' not found`) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | @ -413,17 +436,18 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> { | ||||||
|         const before = Translations.T(input.before) |         const before = Translations.T(input.before) | ||||||
|         const after = Translations.T(input.after) |         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) |             foundLanguages.add(ln) | ||||||
|         } |         } | ||||||
|         for (const ln of Object.keys(after?.translations??{})) { |         for (const ln of Object.keys(after?.translations ?? {})) { | ||||||
|             foundLanguages.add(ln) |             foundLanguages.add(ln) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         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})}` | ||||||
|  |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const result = {} |         const result = {} | ||||||
|  | @ -433,9 +457,9 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> { | ||||||
|             const args = [] |             const args = [] | ||||||
|             for (const argName of argNamesList) { |             for (const argName of argNamesList) { | ||||||
|                 const v = special[argName] ?? "" |                 const v = special[argName] ?? "" | ||||||
|                 if(Translations.isProbablyATranslation(v)){ |                 if (Translations.isProbablyATranslation(v)) { | ||||||
|                     args.push(new Translation(v).textFor(ln)) |                     args.push(new Translation(v).textFor(ln)) | ||||||
|                 }else{ |                 } else { | ||||||
|                     args.push(v) |                     args.push(v) | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | @ -470,16 +494,16 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> { | ||||||
|     convert(json: TagRenderingConfigJson, context: string): { result: TagRenderingConfigJson; errors?: string[]; warnings?: string[]; information?: string[] } { |     convert(json: TagRenderingConfigJson, context: string): { result: TagRenderingConfigJson; errors?: string[]; warnings?: string[]; information?: string[] } { | ||||||
|         const errors = [] |         const errors = [] | ||||||
|         json = Utils.Clone(json) |         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) { |         for (const path of paths) { | ||||||
|             if(path.typeHint !== "rendered"){ |             if (path.typeHint !== "rendered") { | ||||||
|                 continue |                 continue | ||||||
|             } |             } | ||||||
|             Utils.WalkPath(path.path, json, ((leaf, travelled) => RewriteSpecial.convertIfNeeded(leaf, errors, travelled.join(".")))) |             Utils.WalkPath(path.path, json, ((leaf, travelled) => RewriteSpecial.convertIfNeeded(leaf, errors, travelled.join(".")))) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return { |         return { | ||||||
|             result:json, |             result: json, | ||||||
|             errors |             errors | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
|  | @ -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))) | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -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 { | ||||||
|  |  | ||||||
|  | @ -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
									
								
							
							
						
						
									
										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", |     "phone", | ||||||
|     "email", |     "email", | ||||||
|     { |     { | ||||||
|       "id": "language", |       "builtin": "wikidata.school-language", | ||||||
|       "question": { |       "override": { | ||||||
|         "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>", |         "+mappings": [ | ||||||
|         "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>", |             "if": "school:language=", | ||||||
|         "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>" |             "hideInAnswer": true, | ||||||
|       }, |             "then": { | ||||||
|       "render": { |               "en": "The main language of this school is unknown", | ||||||
|         "en": "{school:language} is the main language of {title()}", |               "nl": "De voertaal van deze school is niet gekend" | ||||||
|         "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" |  | ||||||
|           } |           } | ||||||
|         }, |         ], | ||||||
|         { |         "question": { | ||||||
|           "if": "school:language=french", |           "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>", | ||||||
|           "then": { |           "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>", | ||||||
|             "en": "French is the main language of {name}", |           "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>", | ||||||
|             "nl": "Frans is de voertaal van {name}", |           "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>" | ||||||
|             "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": [ | ||||||
|  |  | ||||||
|  | @ -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", | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
							
								
								
									
										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