From 4fcd3523b77043160159316406018e2bc5815aa9 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Fri, 1 Oct 2021 04:49:19 +0200 Subject: [PATCH] Add check that translation for a certain theme is complete, add a few missing dutch translations --- Models/ThemeConfig/Json/LayoutConfigJson.ts | 5 ++++ Models/ThemeConfig/LayerConfig.ts | 4 ++++ Models/ThemeConfig/LayoutConfig.ts | 2 +- UI/i18n/Translation.ts | 18 ++++++++++++++ assets/layers/toilet/toilet.json | 9 ++++--- assets/themes/natuurpunt/natuurpunt.json | 3 +++ scripts/generateLayerOverview.ts | 26 +++++++++++++++++++++ 7 files changed, 63 insertions(+), 4 deletions(-) diff --git a/Models/ThemeConfig/Json/LayoutConfigJson.ts b/Models/ThemeConfig/Json/LayoutConfigJson.ts index 73caee792..89439f529 100644 --- a/Models/ThemeConfig/Json/LayoutConfigJson.ts +++ b/Models/ThemeConfig/Json/LayoutConfigJson.ts @@ -52,6 +52,11 @@ export interface LayoutConfigJson { */ language: string | string[]; + /** + * Only used in 'generateLayerOverview': if present, every translation will be checked to make sure it is fully translated + */ + mustHaveLanguage?: string[] + /** * The title, as shown in the welcome message and the more-screen */ diff --git a/Models/ThemeConfig/LayerConfig.ts b/Models/ThemeConfig/LayerConfig.ts index 1e8fae148..a2e55d71c 100644 --- a/Models/ThemeConfig/LayerConfig.ts +++ b/Models/ThemeConfig/LayerConfig.ts @@ -302,6 +302,10 @@ export default class LayerConfig { this.filters = (json.filter ?? []).map((option, i) => { return new FilterConfig(option, `${context}.filter-[${i}]`) }); + + if(json["filters"] !== undefined){ + throw "Error in "+context+": use 'filter' instead of 'filters'" + } const titleIcons = []; const defaultIcons = [ diff --git a/Models/ThemeConfig/LayoutConfig.ts b/Models/ThemeConfig/LayoutConfig.ts index 4f8551632..8b10f6c54 100644 --- a/Models/ThemeConfig/LayoutConfig.ts +++ b/Models/ThemeConfig/LayoutConfig.ts @@ -81,7 +81,7 @@ export default class LayoutConfig { this.title = new Translation(json.title, context + ".title"); this.description = new Translation(json.description, context + ".description"); this.shortDescription = json.shortDescription === undefined ? this.description.FirstSentence() : new Translation(json.shortDescription, context + ".shortdescription"); - this.descriptionTail = json.descriptionTail === undefined ? new Translation({"*": ""}, context + ".descriptionTail") : new Translation(json.descriptionTail, context + ".descriptionTail"); + this.descriptionTail = json.descriptionTail === undefined ? undefined : new Translation(json.descriptionTail, context + ".descriptionTail"); this.icon = json.icon; this.socialImage = json.socialImage; this.startZoom = json.startZoom; diff --git a/UI/i18n/Translation.ts b/UI/i18n/Translation.ts index 796c52e8d..15bff437a 100644 --- a/UI/i18n/Translation.ts +++ b/UI/i18n/Translation.ts @@ -196,4 +196,22 @@ export class Translation extends BaseUIElement { return allIcons.filter(icon => icon != undefined) } + static ExtractAllTranslationsFrom(object: any, context = ""): { context: string, tr: Translation }[] { + const allTranslations: { context: string, tr: Translation }[] = [] + for (const key in object) { + const v = object[key] + if (v === undefined || v === null) { + continue + } + if (v instanceof Translation) { + allTranslations.push({context: context +"." + key, tr: v}) + continue + } + if (typeof v === "object") { + allTranslations.push(...Translation.ExtractAllTranslationsFrom(v, context + "." + key)) + continue + } + } + return allTranslations + } } \ No newline at end of file diff --git a/assets/layers/toilet/toilet.json b/assets/layers/toilet/toilet.json index 8b10b35ee..d7592efc7 100644 --- a/assets/layers/toilet/toilet.json +++ b/assets/layers/toilet/toilet.json @@ -461,7 +461,8 @@ "options": [ { "question": { - "en": "Wheelchair accessible" + "en": "Wheelchair accessible", + "nl": "Rolstoel toegankelijk" }, "osmTags": "wheelchair=yes" } @@ -472,7 +473,8 @@ "options": [ { "question": { - "en": "Has a changing table" + "en": "Has a changing table", + "nl": "Heeft een luiertafel" }, "osmTags": "changing_table=yes" } @@ -483,7 +485,8 @@ "options": [ { "question": { - "en": "Free to use" + "en": "Free to use", + "nl": "Gratis toegankelijk" }, "osmTags": { "or": [ diff --git a/assets/themes/natuurpunt/natuurpunt.json b/assets/themes/natuurpunt/natuurpunt.json index 7ebcab3b5..4b49e7465 100644 --- a/assets/themes/natuurpunt/natuurpunt.json +++ b/assets/themes/natuurpunt/natuurpunt.json @@ -17,6 +17,9 @@ "nl", "en" ], + "mustHaveLanguage": [ + "nl" + ], "maintainer": "", "icon": "./assets/themes/natuurpunt/natuurpunt.png", "version": "0", diff --git a/scripts/generateLayerOverview.ts b/scripts/generateLayerOverview.ts index 969f9e9b7..d97c235cb 100644 --- a/scripts/generateLayerOverview.ts +++ b/scripts/generateLayerOverview.ts @@ -5,6 +5,8 @@ import {LayoutConfigJson} from "../Models/ThemeConfig/Json/LayoutConfigJson"; import LayoutConfig from "../Models/ThemeConfig/LayoutConfig"; import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson"; import LayerConfig from "../Models/ThemeConfig/LayerConfig"; +import {Translation} from "../UI/i18n/Translation"; +import {Utils} from "../Utils"; // 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 @@ -139,6 +141,16 @@ class LayerOverviewUtils { } } } + + const referencedLayers = Utils.NoNull(themeFile.layers.map(layer => { + if(typeof layer === "string"){ + return layer + } + if(layer["builtin"] !== undefined){ + return layer["builtin"] + } + return undefined + })) themeFile.layers = themeFile.layers .filter(l => typeof l != "string") // We remove all the builtin layer references as they don't work with ts-node for some weird reason @@ -154,6 +166,20 @@ class LayerOverviewUtils { if (theme.id !== filename) { themeErrorCount.push("Theme ids should be the same as the name.json, but we got id: " + theme.id + " and filename " + filename + " (" + themePath + ")") } + const neededLanguages = themeFile["mustHaveLanguage"] + if (neededLanguages !== undefined) { + console.log("Checking language requerements for ", theme.id, "as it must have", neededLanguages.join(", ")) + const allTranslations = [].concat(Translation.ExtractAllTranslationsFrom(theme, theme.id), ...referencedLayers.map(layerId => Translation.ExtractAllTranslationsFrom(knownLayerIds.get(layerId), theme.id+"->"+layerId))) + for (const neededLanguage of neededLanguages) { + allTranslations + .filter(t => t.tr.translations[neededLanguage] === undefined && t.tr.translations["*"] === undefined) + .forEach(missing => { + themeErrorCount.push("The theme " + theme.id + " should be translation-complete for " + neededLanguage + ", but it lacks a translation for " + missing.context) + }) + } + + + } } catch (e) { themeErrorCount.push("Could not parse theme " + themeFile["id"] + "due to", e)