From 159c317548b1e89f037526515327822655cccee8 Mon Sep 17 00:00:00 2001 From: Jay LaPorte Date: Tue, 14 Jan 2020 09:46:00 -0500 Subject: [PATCH 1/4] fix up the English translations --- lib/lang/en.js | 77 +++++++++++++++++++++++++++++----------------- test_cases/en.json | 11 +++++-- 2 files changed, 57 insertions(+), 31 deletions(-) diff --git a/lib/lang/en.js b/lib/lang/en.js index 8914e4f7..f65b477e 100644 --- a/lib/lang/en.js +++ b/lib/lang/en.js @@ -6,26 +6,41 @@ function join_with_shared_prefix(a, b, joiner) { // HACK: This gets around "today through on Tuesday" or cases like it, which // are incorrect in English. - if(m === "today" || m === "tomorrow") + if(m === "today" || m === "tomorrow") { m = "on " + m; + } - while(i !== m.length && - i !== b.length && - m.charCodeAt(i) === b.charCodeAt(i)) + // Skip the prefix of b that is shared with a. + while( + i !== m.length && + i !== b.length && + m.charCodeAt(i) === b.charCodeAt(i) + ) { ++i; + } - while(i && m.charCodeAt(i - 1) !== 32) + // ...except whitespace! We need that whitespace! + while(i && b.charCodeAt(i - 1) !== 32) { --i; + } return a + joiner + b.slice(i); } function strip_prefix(period) { - return period.slice(0, 9) === "overnight" ? period.slice(4) : - period.slice(0, 7) === "in the " ? period.slice(7) : + return period.startsWith("overnight")? period.slice(4): + period.startsWith("in the ")? period.slice(7): period; } +function capitalize(str) { + // Do not capitalize articles, very short words, or units. + if(str === "and" || str === "of" || str === "in" || str === "cm") { + return str; + } + return str[0].toUpperCase() + str.slice(1); +} + module.exports = { "clear": "clear", "no-precipitation": "no precipitation", @@ -104,11 +119,7 @@ module.exports = { "centimeters": "$1 cm.", "less-than": "< $1", "and": function(a, b) { - return join_with_shared_prefix( - a, - b, - a.indexOf(",") !== -1 ? ", and " : " and " - ); + return join_with_shared_prefix(a, b, a.includes(",")? ", and ": " and "); }, "through": function(a, b) { return join_with_shared_prefix(a, b, " through "); @@ -116,7 +127,21 @@ module.exports = { "with": "$1, with $2", "range": "$1\u2013$2", "parenthetical": function(a, b) { - return a + " (" + b + (a === "mixed precipitation" ? " of snow)" : ")"); + // In the case of mixed precipitation, we want to clarify that the + // snow accumulation in the parenthetical is snow. In the case that it's + // of an unknown type or rain or sleet, we want to clarify that while snow + // isn't expected, it has a chance of occurring. The below checks do this. + + // HACK: These are not the best ways to determine the precipitation type... + const is_mixed = a.startsWith("mixed"); + const is_snow = a.endsWith("flurries") || a.endsWith("snow"); + if(!is_mixed && !is_snow) { + b = "chance of " + b; + } + if(!is_snow) { + b = b + " of snow"; + } + return a + " (" + b + ")"; }, "for-hour": "$1 for the hour", "starting-in": "$1 starting in $2", @@ -141,29 +166,25 @@ module.exports = { "temperatures-rising": "high temperatures rising to $1 $2", "temperatures-valleying": "high temperatures bottoming out at $1 $2", "temperatures-falling": "high temperatures falling to $1 $2", - // Capitalize the first letter of every word, except if that word is - // "and". (This is a very crude bastardization of proper English titling - // rules, but it is adequate for the purposes of this module.) + // Capitalize the first letter of every word except "and", "or", and units. + // (This is a very crude bastardization of proper English titling rules, but + // it is adequate for the purposes of this module.) "title": function(str) { - return str.replace( - /\b(?:a(?!nd\b)|c(?!m\.)|i(?!n\.)|[^\Waci])/g, - function(letter) { - return letter.toUpperCase(); - } - ); + return str.replace(/\w+/g, capitalize); }, - /* Capitalize the first word of the sentence and end with a period. */ + // Capitalize the first word of the sentence and end with a period. "sentence": function(str) { - /* Capitalize. */ - str = str.charAt(0).toUpperCase() + str.slice(1); + // Capitalize. + str = capitalize(str); - /* Add a period if there isn't already one. */ - if(str.charAt(str.length - 1) !== ".") + // Add a period if there isn't already one. + if(!str.endsWith(".")) { str += "."; + } return str; }, - "next-hour-forecast-status": "Next hour forecasts are $1 due to $2.", + "next-hour-forecast-status": "next hour forecasts are $1 due to $2", "unavailable": "unavailable", "temporarily-unavailable": "temporarily unavailable", "partially-unavailable": "partially unavailable", diff --git a/test_cases/en.json b/test_cases/en.json index 725aabe7..5f99f3b9 100644 --- a/test_cases/en.json +++ b/test_cases/en.json @@ -249,6 +249,9 @@ "Heavy Snow (3\u20135 cm.)": ["title", ["parenthetical", "heavy-snow", ["centimeters", ["range", 3, 5]]]], + "Rain (Chance of 2\u20134 in. of Snow)": + ["title", ["parenthetical", "medium-rain", ["inches", ["range", 2, 4]]]], + "Possible Thunderstorms": ["title", "possible-thunderstorm"], @@ -260,9 +263,11 @@ ["starting-in", "very-light-rain", ["less-than", ["minutes", 1]]]], "Next hour forecasts are temporarily unavailable due to all nearby radar stations being offline.": - ["sentence",["next-hour-forecast-status", "temporarily-unavailable", "station-offline"]], + ["sentence", ["next-hour-forecast-status", "temporarily-unavailable", "station-offline"]], + "Next hour forecasts are partially unavailable due to gaps in coverage from nearby radar stations.": - ["sentence",["next-hour-forecast-status", "partially-unavailable", "station-incomplete"]], + ["sentence", ["next-hour-forecast-status", "partially-unavailable", "station-incomplete"]], + "Next hour forecasts are unavailable due to all nearby radar stations being offline.": - ["sentence",["next-hour-forecast-status", "unavailable", "station-offline"]] + ["sentence", ["next-hour-forecast-status", "unavailable", "station-offline"]] } From ebeace49fc9e9ab9703bf03a974dfcd4f4f11bd3 Mon Sep 17 00:00:00 2001 From: Jay LaPorte Date: Tue, 14 Jan 2020 09:53:31 -0500 Subject: [PATCH 2/4] clarify docs --- README.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ab739f2f..d70896aa 100644 --- a/README.md +++ b/README.md @@ -456,10 +456,15 @@ would be `["during", "rain", "next-wednesday"]`. * `RAIN_TYPE` * `SLEET_TYPE` * `SNOW_TYPE` -* `["parenthetical", SNOW_TYPE, SNOW_ACCUMULATION]`: For daily or weekly - summaries, if a significant amount of snow is expected, we will qualify it - with the amount of expected snow accumulation on the ground. (For example, - "snow (3-4 in.) throughout the day".) +* `["parenthetical", EXPECTED_PRECIP_TYPE, SNOW_ACCUMULATION]`: For daily or + weekly summaries, if a significant amount of snow is expected, we will + qualify it with the amount of expected snow accumulation. (For example, + "snow (3-4 in.) throughout the day".) PLEASE NOTE that it is possible for a + chance of snow accumulation to be forecasted even if the expected + precipitation type is rain or sleet: this may occur if the forecasted + temperature is right around the freezing point. Translations should clarify + that the parenthetical refers to a chance of snow in such circumstances. + (For example, "sleet (chance of 3-4 in. of snow) throughout the day".) In each of the below precipitation types, the intensity of precipitation is (very approximately) as follows: From 4e268a7513d85078557d94a79035e43d81db61cc Mon Sep 17 00:00:00 2001 From: Jay LaPorte Date: Tue, 14 Jan 2020 10:36:18 -0500 Subject: [PATCH 3/4] tweak translation --- lib/lang/en.js | 11 +++++++++-- test_cases/en.json | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/lang/en.js b/lib/lang/en.js index f65b477e..6af3c2b7 100644 --- a/lib/lang/en.js +++ b/lib/lang/en.js @@ -35,7 +35,14 @@ function strip_prefix(period) { function capitalize(str) { // Do not capitalize articles, very short words, or units. - if(str === "and" || str === "of" || str === "in" || str === "cm") { + if( + str === "a" || + str === "and" || + str === "cm" || + str === "in" || + str === "of" || + str === "with" + ) { return str; } return str[0].toUpperCase() + str.slice(1); @@ -136,7 +143,7 @@ module.exports = { const is_mixed = a.startsWith("mixed"); const is_snow = a.endsWith("flurries") || a.endsWith("snow"); if(!is_mixed && !is_snow) { - b = "chance of " + b; + b = "with a chance of " + b; } if(!is_snow) { b = b + " of snow"; diff --git a/test_cases/en.json b/test_cases/en.json index 5f99f3b9..88474a0e 100644 --- a/test_cases/en.json +++ b/test_cases/en.json @@ -249,7 +249,7 @@ "Heavy Snow (3\u20135 cm.)": ["title", ["parenthetical", "heavy-snow", ["centimeters", ["range", 3, 5]]]], - "Rain (Chance of 2\u20134 in. of Snow)": + "Rain (with a Chance of 2\u20134 in. of Snow)": ["title", ["parenthetical", "medium-rain", ["inches", ["range", 2, 4]]]], "Possible Thunderstorms": From 7b88317520bca278b3445ba3036db381bbe51162 Mon Sep 17 00:00:00 2001 From: Jay LaPorte Date: Tue, 14 Jan 2020 13:07:36 -0500 Subject: [PATCH 4/4] minor tidyup --- lib/lang/en.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/lang/en.js b/lib/lang/en.js index 6af3c2b7..9220f56a 100644 --- a/lib/lang/en.js +++ b/lib/lang/en.js @@ -45,6 +45,7 @@ function capitalize(str) { ) { return str; } + return str[0].toUpperCase() + str.slice(1); } @@ -140,14 +141,13 @@ module.exports = { // isn't expected, it has a chance of occurring. The below checks do this. // HACK: These are not the best ways to determine the precipitation type... - const is_mixed = a.startsWith("mixed"); - const is_snow = a.endsWith("flurries") || a.endsWith("snow"); - if(!is_mixed && !is_snow) { - b = "with a chance of " + b; - } - if(!is_snow) { - b = b + " of snow"; + if(!a.endsWith("flurries") && !a.endsWith("snow")) { + if(!a.startsWith("mixed")) { + b = "with a chance of " + b; + } + b += " of snow"; } + return a + " (" + b + ")"; }, "for-hour": "$1 for the hour",