From 42ddbcb9b46e23d7c3f2f1ba5014080fad2beee1 Mon Sep 17 00:00:00 2001 From: Boris Verkhovskiy Date: Mon, 22 Apr 2024 06:13:57 -0700 Subject: [PATCH 1/2] Mark translatable strings --- js/ide.ts | 38 +++++++++++---------- js/overpass.ts | 91 ++++++++++++++++++++++++++++++------------------- js/popup.ts | 33 +++++++++++++----- locales/en.json | 39 +++++++++++++++++++++ 4 files changed, 139 insertions(+), 62 deletions(-) diff --git a/js/ide.ts b/js/ide.ts index eac2b205..a77c3b67 100644 --- a/js/ide.ts +++ b/js/ide.ts @@ -203,7 +203,9 @@ class IDE { if (typeof abortCallback == "function") { this.onAbort = abortCallback; const aborter = $( - ' (abort)' + ` (${i18n.t( + "waiter.abort" + )})` ).on("click", () => { this.abort(); return false; @@ -214,7 +216,7 @@ class IDE { } abort() { if (typeof this.onAbort == "function") { - this.addInfo("aborting"); + this.addInfo(i18n.t("waiter.aborting")); this.onAbort(this.close); } } @@ -223,7 +225,7 @@ class IDE { // == public methods == init() { - this.waiter.addInfo("ide starting up"); + this.waiter.addInfo(i18n.t("waiter.ide_starting_up")); $("#overpass-turbo-version").html( `overpass-turbo ${GIT_VERSION}` // eslint-disable-line no-undef ); @@ -250,10 +252,10 @@ class IDE { $("#warning-unsupported-browser").addClass("is-active"); } // load settings - this.waiter.addInfo("load settings"); + this.waiter.addInfo(i18n.t("waiter.load_settings")); settings.load(); // translate ui - this.waiter.addInfo("translate ui"); + this.waiter.addInfo(i18n.t("waiter.translate_ui")); i18n.translate().then(() => this.initAfterI18n()); if (sync.enabled) { @@ -269,7 +271,7 @@ class IDE { // eslint-disable-next-line @typescript-eslint/no-this-alias const ide = this; // parse url string parameters - ide.waiter.addInfo("parse url parameters"); + ide.waiter.addInfo(i18n.t("waiter.parse_url_parameters")); const args = urlParameters(); // set appropriate settings if (args.has_coords) { @@ -287,7 +289,7 @@ class IDE { } settings.save(); - ide.waiter.addInfo("initialize page"); + ide.waiter.addInfo(i18n.t("waiter.initialize_page")); // init page layout const isInitialAspectPortrait = $(window).width() / $(window).height() < 0.8; @@ -468,7 +470,7 @@ class IDE { } // init dataviewer ide.dataViewer = CodeMirror($("#data")[0], { - value: "no data loaded yet", + value: i18n.t("editor.no_data_loaded"), lineNumbers: true, readOnly: true, mode: "javascript" @@ -865,7 +867,7 @@ class IDE { const isCountPresent = /out[^;]+?count/.test(query); // show warning/info if only invisible data is returned and 'out...count' is not present in the query - if (empty_msg == "no visible data") { + if (empty_msg == "waiter.no_visible_data") { if (!isCountPresent && !settings.no_autorepair) { const content = `

${i18n.t( "warning.incomplete.expl.1" @@ -905,16 +907,16 @@ class IDE { } } // auto tab switching (if only areas are returned) - if (empty_msg == "only areas returned") ide.switchTab("Data"); + if (empty_msg == "waiter.only_areas_returned") ide.switchTab("Data"); // auto tab switching (if nodes without coordinates are returned) - if (empty_msg == "no coordinates returned") ide.switchTab("Data"); + if (empty_msg == "waiter.no_coordinates_returned") ide.switchTab("Data"); // auto tab switching (if unstructured data is returned) if (data_mode == "unknown") ide.switchTab("Data"); // display empty map badge $( `

${i18n.t( "map.intentionally_blank" - )} (${empty_msg})
` + )} (${i18n.t(empty_msg)})` ).appendTo("#map"); }; overpass.handlers["onDataReceived"] = function ( @@ -2211,14 +2213,14 @@ class IDE { // 1. render canvas from map tiles // hide map controlls in this step :/ // todo: also hide popups? - this.waiter.addInfo("prepare map"); + this.waiter.addInfo(i18n.t("waiter.prepare_map")); $("#map .leaflet-control-container .leaflet-top").hide(); $("#data_stats").hide(); if (settings.export_image_attribution) this.map.addControl(this.attribControl); if (!settings.export_image_scale) this.map.removeControl(this.scaleControl); // try to use crossOrigin image loading. osm tiles should be served with the appropriate headers -> no need of bothering the proxy - this.waiter.addInfo("rendering map tiles"); + this.waiter.addInfo(i18n.t("waiter.rendering_map_tiles")); $("#map .leaflet-overlay-pane").hide(); const canvas = await html2canvas(document.getElementById("map"), { useCORS: true, @@ -2231,7 +2233,7 @@ class IDE { if (!settings.export_image_scale) this.map.addControl(this.scaleControl); if (settings.show_data_stats) $("#data_stats").show(); $("#map .leaflet-control-container .leaflet-top").show(); - this.waiter.addInfo("rendering map data"); + this.waiter.addInfo(i18n.t("waiter.rendering_map_data")); // 2. render overlay data onto canvas canvas.id = "render_canvas"; const ctx = canvas.getContext("2d"); @@ -2257,7 +2259,7 @@ class IDE { }); v.render(); } - this.waiter.addInfo("converting to png image"); + this.waiter.addInfo(i18n.t("waiter.converting_to_png_image")); // 3. export canvas as html image const imgstr = canvas.toDataURL("image/png"); let attrib_message = ""; @@ -2585,7 +2587,7 @@ class IDE { } async update_map() { this.waiter.open(i18n.t("waiter.processing_query")); - this.waiter.addInfo("resetting map"); + this.waiter.addInfo(i18n.t("waiter.resetting_map")); $("#data_stats").remove(); // resets previously highlighted error lines this.resetErrors(); @@ -2595,7 +2597,7 @@ class IDE { this.map.removeLayer(overpass.osmLayer); $("#map_blank").remove(); - this.waiter.addInfo("building query"); + this.waiter.addInfo(i18n.t("waiter.building_query")); // run the query via the overpass object const query = await this.getQuery(); if (configs.push_history_url && typeof history.pushState == "function") { diff --git a/js/overpass.ts b/js/overpass.ts index 861e849d..7bd0a4ac 100644 --- a/js/overpass.ts +++ b/js/overpass.ts @@ -7,6 +7,7 @@ import L_OSM4Leaflet from "./OSM4Leaflet"; import L_GeoJsonNoVanish from "./GeoJsonNoVanish"; import configs from "./configs"; +import i18n from "./i18n"; import settings from "./settings"; import {htmlentities} from "./misc"; import styleparser from "./jsmapcss"; @@ -80,21 +81,17 @@ class Overpass { query = `${query}`; } } - overpass.fire( - "onProgress", - "calling Overpass API interpreter", - (callback) => { - // kill the query on abort - overpass.ajax_request.abort(); - // try to abort queries via kill_my_queries - $.get(`${server}kill_my_queries`) - .done(callback) - .fail(() => { - console.log("Warning: failed to kill query."); - callback(); - }); - } - ); + overpass.fire("onProgress", i18n.t("waiter.calling_api"), (callback) => { + // kill the query on abort + overpass.ajax_request.abort(); + // try to abort queries via kill_my_queries + $.get(`${server}kill_my_queries`) + .done(callback) + .fail(() => { + console.log("Warning: failed to kill query."); + callback(); + }); + }); function onSuccessCb(data, textStatus, jqXHR) { //textStatus is not needed in the successCallback, don't cache it if (cache) cache[query] = [data, undefined, jqXHR]; @@ -105,10 +102,15 @@ class Overpass { const scale = Math.floor(Math.log(data_amount) / Math.log(10)); data_amount = Math.round(data_amount / Math.pow(10, scale)) * Math.pow(10, scale); - if (data_amount < 1000) data_txt = `${data_amount} bytes`; - else if (data_amount < 1000000) data_txt = `${data_amount / 1000} kB`; - else data_txt = `${data_amount / 1000000} MB`; - overpass.fire("onProgress", `received about ${data_txt} of data`); + if (data_amount < 1000) + data_txt = `${data_amount} ${i18n.t("waiter.bytes")}`; + else if (data_amount < 1000000) + data_txt = `${data_amount / 1000} ${i18n.t("waiter.kilobytes")}`; + else data_txt = `${data_amount / 1000000} ${i18n.t("waiter.megabytes")}`; + overpass.fire( + "onProgress", + i18n.t("waiter.received_data").replace("{{data_amount}}", data_txt) + ); overpass.fire( "onDataReceived", data_amount, @@ -138,7 +140,7 @@ class Overpass { }; overpass.ajax_request_duration = Date.now() - overpass.ajax_request_start; - overpass.fire("onProgress", "parsing data"); + overpass.fire("onProgress", i18n.t("waiter.parsing_data")); setTimeout(() => { // hacky firefox hack :( (it is not properly detecting json from the content-type header) if (typeof data == "string" && data[0] == "{") { @@ -418,7 +420,7 @@ class Overpass { overpass.osmLayer = new L_OSM4Leaflet(null, { afterParse() { - overpass.fire("onProgress", "rendering geoJSON"); + overpass.fire("onProgress", i18n.t("waiter.rendering")); }, baseLayerClass: L_GeoJsonNoVanish, baseLayerOptions: { @@ -631,7 +633,10 @@ class Overpass { if (!shouldCacheOnly) overpass.fire("onGeoJsonReady"); // print raw data - overpass.fire("onProgress", "printing raw data"); + overpass.fire( + "onProgress", + i18n.t("waiter.printing_raw_data") + ); setTimeout(() => { overpass.resultText = jqXHR.responseText; overpass.fire("onRawDataPresent"); @@ -657,7 +662,7 @@ class Overpass { .children() .not("note,meta,bounds,area").length == 0) ) - empty_msg = "only areas returned"; + empty_msg = "waiter.only_areas_returned"; else if ( (data_mode == "json" && _.some(data.elements, {type: "node"})) || @@ -665,7 +670,7 @@ class Overpass { $("osm", data).children().filter("node").length > 0) ) // check for "ids_only" or "tags" on nodes - empty_msg = "no coordinates returned"; + empty_msg = "waiter.no_coordinates_returned"; else if ( (data_mode == "json" && _.some(data.elements, {type: "way"}) && @@ -683,7 +688,7 @@ class Overpass { .filter("nd").length == 0) ) // check for "ids_only" or "tags" on ways - empty_msg = "no coordinates returned"; + empty_msg = "waiter.no_coordinates_returned"; else if ( (data_mode == "json" && _.some(data.elements, {type: "relation"}) && @@ -701,14 +706,14 @@ class Overpass { .filter("member").length == 0) ) // check for "ids_only" or "tags" on relations - empty_msg = "no coordinates returned"; - else empty_msg = "no visible data"; + empty_msg = "waiter.no_coordinates_returned"; + else empty_msg = "waiter.no_visible_data"; } else if (data_mode == "error") { - empty_msg = "an error occured"; + empty_msg = "waiter.an_error_occured"; } else if (data_mode == "unknown") { - empty_msg = "unstructured data returned"; + empty_msg = "waiter.unstructured_data_returned"; } else { - empty_msg = "received empty dataset"; + empty_msg = "waiter.received_empty_dataset"; } // show why there is an empty map overpass.fire("onEmptyMap", empty_msg, data_mode); @@ -736,7 +741,7 @@ class Overpass { success: onSuccessCb, error(jqXHR, textStatus) { if (textStatus == "abort") return; // ignore aborted queries. - overpass.fire("onProgress", "error during ajax call"); + overpass.fire("onProgress", i18n.t("waiter.error_during_ajax_call")); if ( jqXHR.status == 400 || jqXHR.status == 504 || @@ -750,17 +755,31 @@ class Overpass { overpass.resultText = jqXHR.resultText; let errmsg = ""; if (jqXHR.state() == "rejected") - errmsg += - "

Request rejected. (e.g. server not found, request blocked by browser addon, request redirected, internal server errors, etc.)

"; + errmsg += "

" + i18n.t("waiter.request_rejected") + "

"; if (textStatus == "parsererror") - errmsg += "

Error while parsing the data (parsererror).

"; + errmsg += + "

" + + i18n + .t("waiter.parse_error") + .replace("{{textStatus}}", textStatus) + + "

"; else if (textStatus != "error" && textStatus != jqXHR.statusText) - errmsg += `

Error-Code: ${textStatus}

`; + errmsg += + "

" + + i18n + .t("waiter.error_code") + .replace("{{textStatus}}", textStatus) + + "

"; if ( (jqXHR.status != 0 && jqXHR.status != 200) || jqXHR.statusText != "OK" // note to me: jqXHR.status "should" give http status codes ) - errmsg += `

Error-Code: ${jqXHR.statusText} (${jqXHR.status})

`; + errmsg += + "

" + + i18n + .t("waiter.error_code") + .replace("{{textStatus}}", jqXHR.statusText) + + ` (${jqXHR.status})

`; overpass.fire("onAjaxError", errmsg); // closing wait spinner overpass.fire("onDone"); diff --git a/js/popup.ts b/js/popup.ts index d5fb7cd0..7c5f2b09 100644 --- a/js/popup.ts +++ b/js/popup.ts @@ -1,4 +1,5 @@ import $ from "jquery"; +import i18n from "./i18n"; import {htmlentities} from "./misc"; import tag2link from "tag2link/index.json"; @@ -10,19 +11,25 @@ export function featurePopupContent(feature: GeoJSON.Feature) { let popup = ""; if (feature.properties.type == "node") popup += - `

Node` + + `

${i18n.t( + "popup.node" + )}` + ` ${feature.properties.id}` + ` ` + `

`; else if (feature.properties.type == "way") popup += - `

Way` + + `

${i18n.t( + "popup.way" + )}` + ` ${feature.properties.id}` + ` ` + `

`; else if (feature.properties.type == "relation") popup += - `

Relation` + + `

${i18n.t( + "popup.relation" + )}` + ` ${feature.properties.id}` + ` ` + `

`; @@ -33,7 +40,9 @@ export function featurePopupContent(feature: GeoJSON.Feature) { feature.properties.tags && !$.isEmptyObject(feature.properties.tags) ) { - popup += `
Tags`; + popup += `
${i18n.t( + "tags" + )}`; if (typeof Object.keys === "function") { popup += ` ${ Object.keys(feature.properties.tags).length @@ -107,7 +116,9 @@ export function featurePopupContent(feature: GeoJSON.Feature) { feature.properties.relations && !$.isEmptyObject(feature.properties.relations) ) { - popup += `

Relations`; + popup += `

${i18n.t( + "relations" + )}`; if (typeof Object.keys === "function") { popup += ` ${ Object.keys(feature.properties.relations).length @@ -132,7 +143,9 @@ export function featurePopupContent(feature: GeoJSON.Feature) { feature.properties.meta && !$.isEmptyObject(feature.properties.meta) ) { - popup += `

Metadata

    `; + popup += `

    ${i18n.t( + "metadata" + )}

      `; $.each(feature.properties.meta, (k, v) => { k = htmlentities(k); v = htmlentities(v); @@ -149,7 +162,9 @@ export function featurePopupContent(feature: GeoJSON.Feature) { const lat = feature.geometry.coordinates[1]; const lon = feature.geometry.coordinates[0]; popup += - `

      Coordinates

      ` + + `

      ${i18n.t( + "coordinates" + )}

      ` + `

      ${lat} / ${lon} (lat/lon)

      `; } if ( @@ -160,7 +175,9 @@ export function featurePopupContent(feature: GeoJSON.Feature) { ]) != -1 ) { if (feature.properties && feature.properties.tainted == true) { - popup += `

      Attention: incomplete geometry (e.g. some nodes missing)

      `; + popup += `

      ${i18n.t( + "popup.incomplete_geometry" + )}

      `; } } return popup; diff --git a/locales/en.json b/locales/en.json index cd86a873..6e90fed3 100644 --- a/locales/en.json +++ b/locales/en.json @@ -262,9 +262,48 @@ "warning.huge_data.expl.1": "This query returned quite a lot of data (approx. {{amount_txt}}).", "warning.huge_data.expl.2": "Your browser may have a hard time trying to render this. Do you really want to continue?", + "editor.no_data_loaded": "no data loaded yet", + "waiter.processing_query": "processing query...", "waiter.export_as_image": "exporting as image...", + "waiter.calling_api": "Calling Overpass API interpreter", + "waiter.abort": "abort", + "waiter.aborting": "aborting", + + "waiter.ide_starting_up": "ide starting up", + "waiter.load_settings": "load settings", + "waiter.translate_ui": "translate ui", + "waiter.parse_url_parameters": "parse url parameters", + "waiter.initialize_page": "initialize page", + "waiter.prepare_map": "prepare map", + "waiter.rendering_map_tiles": "rendering map tiles", + "waiter.rendering_map_data": "rendering map data", + "waiter.converting_to_png_image": "converting to png image", + "waiter.resetting_map": "resetting map", + "waiter.building_query": "building query", + + "waiter.only_areas_returned": "only areas returned", + "waiter.no_coordinates_returned": "no coordinates returned", + "waiter.no_visible_data": "no visible data", + "waiter.an_error_occured": "an error occured", + "waiter.unstructured_data_returned": "unstructured data returned", + "waiter.received_empty_dataset": "received empty dataset", + "waiter.printing_raw_data": "printing raw data", + "waiter.error_during_ajax_call": "error during ajax call", + + "waiter.bytes": "bytes", + "waiter.kilobytes": "kB", + "waiter.megabytes": "MB", + "waiter.received_data": "received about {{data_amount}} of data", + + "waiter.parsing_data": "parsing data", + "waiter.rendering": "rendering geoJSON", + + "waiter.request_rejected": "Request rejected. (e.g. server not found, request blocked by browser addon, request redirected, internal server errors, etc.)", + "waiter.parse_error": "Error while parsing the data ({{textStatus}}).", + "waiter.error_code": "Error-Code: {{textStatus}}", + "data_stats.loaded": "Loaded", "data_stats.displayed": "Displayed", "data_stats.nodes": "nodes", From dd5def7f2626800fe07e31025f55cd2f9683d4d6 Mon Sep 17 00:00:00 2001 From: Boris Verkhovskiy Date: Mon, 22 Apr 2024 22:40:25 -0700 Subject: [PATCH 2/2] Unmark a couple strings --- js/ide.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/ide.ts b/js/ide.ts index a77c3b67..55441c56 100644 --- a/js/ide.ts +++ b/js/ide.ts @@ -225,7 +225,7 @@ class IDE { // == public methods == init() { - this.waiter.addInfo(i18n.t("waiter.ide_starting_up")); + this.waiter.addInfo("ide starting up"); $("#overpass-turbo-version").html( `overpass-turbo ${GIT_VERSION}` // eslint-disable-line no-undef ); @@ -252,10 +252,10 @@ class IDE { $("#warning-unsupported-browser").addClass("is-active"); } // load settings - this.waiter.addInfo(i18n.t("waiter.load_settings")); + this.waiter.addInfo("load settings"); settings.load(); // translate ui - this.waiter.addInfo(i18n.t("waiter.translate_ui")); + this.waiter.addInfo("translate ui"); i18n.translate().then(() => this.initAfterI18n()); if (sync.enabled) {