openvibers/openvibe.tours Commits
Wikivoyage's unit templates keep their measure (#44)
Changes
@@@ -30,9 +30,9 @@ function fileTitle(name) {return /^File:/i.test(s) ? s : `File:${s}`;}--// A run under older rules is not fresh (jobs/index.js): inline-templates-1 keeps {{convert}}, {{lang}} and the like in the--// summaries, so the first boot with it rewrites them.--const CITIES_VERSION = 'inline-templates-1';++// A run under older rules is not fresh (jobs/index.js): inline-templates-2 keeps {{convert}}, the unit templates ({{km2}}), {{lang}} and the like++// in the summaries, so the first boot with it rewrites them.++const CITIES_VERSION = 'inline-templates-2';function createCitiesJob({ config, s, store, fetchImpl, log = console }) {const wikivoyage = createWikivoyage({ config, fetchImpl, pace: s.pace });@@@ -26,6 +26,7 @@ function matchingBrace(text, start) {// {{convert|82400|km2}} left Chongqing's lead "…and covers ." (production, 2026-11-02).const UNITS = { km2: 'km²', 'km²': 'km²', sqkm: 'km²', sqmi: 'sq mi', mi2: 'sq mi', km: 'km', mi: 'mi', m: 'm', ft: 'ft', ha: 'ha',acre: 'acres', acres: 'acres', c: '°C', f: '°F', '°c': '°C', '°f': '°F', kg: 'kg', lb: 'lb', 'km/h': 'km/h', mph: 'mph', l: 'L' };++const UNIT_TEMPLATES = { km: 'km', km2: 'km²', m: 'm', m2: 'm²', mi: 'mi', mi2: 'sq mi', sqmi: 'sq mi', ft: 'ft', ft2: 'sq ft', kg: 'kg', lb: 'lb', ha: 'ha', acre: 'acres', kmh: 'km/h', mph: 'mph' };const number = (v) => (/^-?\d+(\.\d+)?$/.test(String(v).trim()) ? Number(v).toLocaleString('en-US', { maximumFractionDigits: 2 }) : String(v).trim());function inlineTemplate(inner) {const parts = splitParams(inner).map((x) => x.trim());@@@ -42,6 +43,9 @@ function inlineTemplate(inner) {const unit = UNITS[String(pos[1] || '').toLowerCase()] || pos[1] || '';return `${number(pos[0])}${unit ? ` ${unit}` : ''}`;}++ // Wikivoyage's unit templates: {{km2|82,403}} is "82,403 km²" ("…and covers ." for Chongqing, 2026-11-02), {{m|28}}++ // is "28 m".++ if (UNIT_TEMPLATES[name] && pos[0]) return `${number(pos[0])} ${UNIT_TEMPLATES[name]}`;if (name === 'lang' || name === 'lang-zh') return pos[pos.length - 1] || '';if (name === 'nowrap' || name === 'nobr' || name === 'small' || name === 'iata' || name === 'icao') return pos[0] || '';if (name === 'w' || name === 'wp') return pos[1] || pos[0] || '';@@@ -17,7 +17,8 @@ function check(name, fn) {check('stripWiki keeps the last character, follows links and removes templates, files and refs', () => {assert.strictEqual(stripWiki('Ueno Park'), 'Ueno Park');assert.strictEqual(stripWiki("[[Tokyo/Asakusa|Asakusa]]'s '''Senso-ji''' is [[Buddhist]].", {}), "Asakusa's Senso-ji is Buddhist.");-- assert.strictEqual(stripWiki('A {{m|28}} statue<ref>source</ref>'), 'A statue');++ assert.strictEqual(stripWiki('A {{m|28}} statue<ref>source</ref>'), 'A 28 m statue', 'a unit template keeps its measure');++ assert.strictEqual(stripWiki('It covers {{km2|82,403}}.'), 'It covers 82,403 km².');// Inline templates that carry words are kept as text (Chongqing's lead ended "covers ." on 2026-11-02).assert.strictEqual(stripWiki('It covers {{convert|82400|km2|sqmi}}.'), 'It covers 82,400 km².');assert.strictEqual(stripWiki('{{convert|20|-|25|km}} away, {{convert|5|to|10|mi}}'), '20–25 km away, 5 to 10 mi');
@@ -30,9 +30,9 @@ function fileTitle(name) {
@@ -30,9 +30,9 @@ function fileTitle(name) {
return /^File:/i.test(s) ? s : `File:${s}`;
return /^File:/i.test(s) ? s : `File:${s}`;
}
}
-// A run under older rules is not fresh (jobs/index.js): inline-templates-1 keeps {{convert}}, {{lang}} and the like in the
-// summaries, so the first boot with it rewrites them.
-const CITIES_VERSION = 'inline-templates-1';
+// A run under older rules is not fresh (jobs/index.js): inline-templates-2 keeps {{convert}}, the unit templates ({{km2}}), {{lang}} and the like
+// in the summaries, so the first boot with it rewrites them.
+const CITIES_VERSION = 'inline-templates-2';
function createCitiesJob({ config, s, store, fetchImpl, log = console }) {
function createCitiesJob({ config, s, store, fetchImpl, log = console }) {
const wikivoyage = createWikivoyage({ config, fetchImpl, pace: s.pace });
const wikivoyage = createWikivoyage({ config, fetchImpl, pace: s.pace });
@@ -26,6 +26,7 @@ function matchingBrace(text, start) {
@@ -26,6 +26,7 @@ function matchingBrace(text, start) {
// {{convert|82400|km2}} left Chongqing's lead "…and covers ." (production, 2026-11-02).
// {{convert|82400|km2}} left Chongqing's lead "…and covers ." (production, 2026-11-02).
const UNITS = { km2: 'km²', 'km²': 'km²', sqkm: 'km²', sqmi: 'sq mi', mi2: 'sq mi', km: 'km', mi: 'mi', m: 'm', ft: 'ft', ha: 'ha',
const UNITS = { km2: 'km²', 'km²': 'km²', sqkm: 'km²', sqmi: 'sq mi', mi2: 'sq mi', km: 'km', mi: 'mi', m: 'm', ft: 'ft', ha: 'ha',
acre: 'acres', acres: 'acres', c: '°C', f: '°F', '°c': '°C', '°f': '°F', kg: 'kg', lb: 'lb', 'km/h': 'km/h', mph: 'mph', l: 'L' };
acre: 'acres', acres: 'acres', c: '°C', f: '°F', '°c': '°C', '°f': '°F', kg: 'kg', lb: 'lb', 'km/h': 'km/h', mph: 'mph', l: 'L' };
+const UNIT_TEMPLATES = { km: 'km', km2: 'km²', m: 'm', m2: 'm²', mi: 'mi', mi2: 'sq mi', sqmi: 'sq mi', ft: 'ft', ft2: 'sq ft', kg: 'kg', lb: 'lb', ha: 'ha', acre: 'acres', kmh: 'km/h', mph: 'mph' };
const number = (v) => (/^-?\d+(\.\d+)?$/.test(String(v).trim()) ? Number(v).toLocaleString('en-US', { maximumFractionDigits: 2 }) : String(v).trim());
const number = (v) => (/^-?\d+(\.\d+)?$/.test(String(v).trim()) ? Number(v).toLocaleString('en-US', { maximumFractionDigits: 2 }) : String(v).trim());
function inlineTemplate(inner) {
function inlineTemplate(inner) {
const parts = splitParams(inner).map((x) => x.trim());
const parts = splitParams(inner).map((x) => x.trim());
@@ -42,6 +43,9 @@ function inlineTemplate(inner) {
@@ -42,6 +43,9 @@ function inlineTemplate(inner) {
const unit = UNITS[String(pos[1] || '').toLowerCase()] || pos[1] || '';
const unit = UNITS[String(pos[1] || '').toLowerCase()] || pos[1] || '';
return `${number(pos[0])}${unit ? ` ${unit}` : ''}`;
return `${number(pos[0])}${unit ? ` ${unit}` : ''}`;
}
}
+ // Wikivoyage's unit templates: {{km2|82,403}} is "82,403 km²" ("…and covers ." for Chongqing, 2026-11-02), {{m|28}}
+ // is "28 m".
+ if (UNIT_TEMPLATES[name] && pos[0]) return `${number(pos[0])} ${UNIT_TEMPLATES[name]}`;
if (name === 'lang' || name === 'lang-zh') return pos[pos.length - 1] || '';
if (name === 'lang' || name === 'lang-zh') return pos[pos.length - 1] || '';
if (name === 'nowrap' || name === 'nobr' || name === 'small' || name === 'iata' || name === 'icao') return pos[0] || '';
if (name === 'nowrap' || name === 'nobr' || name === 'small' || name === 'iata' || name === 'icao') return pos[0] || '';
if (name === 'w' || name === 'wp') return pos[1] || pos[0] || '';
if (name === 'w' || name === 'wp') return pos[1] || pos[0] || '';
@@ -17,7 +17,8 @@ function check(name, fn) {
@@ -17,7 +17,8 @@ function check(name, fn) {
check('stripWiki keeps the last character, follows links and removes templates, files and refs', () => {
check('stripWiki keeps the last character, follows links and removes templates, files and refs', () => {
assert.strictEqual(stripWiki('Ueno Park'), 'Ueno Park');
assert.strictEqual(stripWiki('Ueno Park'), 'Ueno Park');
assert.strictEqual(stripWiki("[[Tokyo/Asakusa|Asakusa]]'s '''Senso-ji''' is [[Buddhist]].", {}), "Asakusa's Senso-ji is Buddhist.");
assert.strictEqual(stripWiki("[[Tokyo/Asakusa|Asakusa]]'s '''Senso-ji''' is [[Buddhist]].", {}), "Asakusa's Senso-ji is Buddhist.");
- assert.strictEqual(stripWiki('A {{m|28}} statue<ref>source</ref>'), 'A statue');
+ assert.strictEqual(stripWiki('A {{m|28}} statue<ref>source</ref>'), 'A 28 m statue', 'a unit template keeps its measure');
+ assert.strictEqual(stripWiki('It covers {{km2|82,403}}.'), 'It covers 82,403 km².');
// Inline templates that carry words are kept as text (Chongqing's lead ended "covers ." on 2026-11-02).
// Inline templates that carry words are kept as text (Chongqing's lead ended "covers ." on 2026-11-02).
assert.strictEqual(stripWiki('It covers {{convert|82400|km2|sqmi}}.'), 'It covers 82,400 km².');
assert.strictEqual(stripWiki('It covers {{convert|82400|km2|sqmi}}.'), 'It covers 82,400 km².');
assert.strictEqual(stripWiki('{{convert|20|-|25|km}} away, {{convert|5|to|10|mi}}'), '20–25 km away, 5 to 10 mi');
assert.strictEqual(stripWiki('{{convert|20|-|25|km}} away, {{convert|5|to|10|mi}}'), '20–25 km away, 5 to 10 mi');