diff --git a/CHANGELOG.md b/CHANGELOG.md index ca0c66b0a..8733e9885 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ _Breaking developer changes, which may affect downstream projects or sites that #### :white_check_mark: Validation * Add warning if aeroways cross each other, buildings or highways ([#9315], thanks [@k-yle]) * Warn when a way with more than the maximum allowed number of nodes is to be uploaded and provide a way to fix it ([#7381]) +* The Suspicious Names validator warning now compares the Name field to the preset’s name in the user’s language, not just the raw tag value (typically in British English). ([#9522], thanks [@k-yle]) * Revalidate ways that are connected to the currently edited way to also properly update/catch _disconnected way_s and _impossible oneway_ errors ([#8911], thanks [@andrewpmk]) #### :bug: Bugfixes * Prevent degenerate ways caused by deleting a corner of a triangle ([#10003], thanks [@k-yle]) @@ -71,6 +72,7 @@ _Breaking developer changes, which may affect downstream projects or sites that [#7381]: https://github.com/openstreetmap/iD/issues/7381 [#8911]: https://github.com/openstreetmap/iD/pull/8911 +[#9522]: https://github.com/openstreetmap/iD/issues/9522 [#9634]: https://github.com/openstreetmap/iD/pull/9634 [#9635]: https://github.com/openstreetmap/iD/pull/9635 [#10003]: https://github.com/openstreetmap/iD/pull/10003 diff --git a/modules/validations/suspicious_name.js b/modules/validations/suspicious_name.js index 369116bec..0a9bcd09d 100644 --- a/modules/validations/suspicious_name.js +++ b/modules/validations/suspicious_name.js @@ -5,7 +5,7 @@ import { t, localizer } from '../core/localizer'; import { validationIssue, validationIssueFix } from '../core/validation'; -export function validationSuspiciousName() { +export function validationSuspiciousName(context) { const type = 'suspicious_name'; const keysToTestForGenericValues = [ 'aerialway', 'aeroway', 'amenity', 'building', 'craft', 'highway', @@ -45,9 +45,17 @@ export function validationSuspiciousName() { return false; } - function isGenericName(name, tags) { + /** @param {string} name @param {string} presetName */ + function nameMatchesPresetName(name, presetName) { + if (!presetName) return false; + + return name.toLowerCase() === presetName.toLowerCase(); + } + + /** @param {string} name @param {string} presetName */ + function isGenericName(name, tags, presetName) { name = name.toLowerCase(); - return nameMatchesRawTag(name, tags) || isGenericMatchInNsi(tags); + return nameMatchesRawTag(name, tags) || nameMatchesPresetName(name, presetName) || isGenericMatchInNsi(tags); } function makeGenericNameIssue(entityId, nameKey, genericName, langCode) { @@ -105,6 +113,8 @@ export function validationSuspiciousName() { let issues = []; + const presetName = presetManager.match(entity, context.graph()).name(); + for (let key in tags) { const m = key.match(/^name(?:(?::)([a-zA-Z_-]+))?$/); if (!m) continue; @@ -112,7 +122,7 @@ export function validationSuspiciousName() { const langCode = m.length >= 2 ? m[1] : null; const value = tags[key]; - if (isGenericName(value, tags)) { + if (isGenericName(value, tags, presetName)) { issues.provisional = _waitingForNsi; // retry later if we are waiting on NSI to finish loading issues.push(makeGenericNameIssue(entity.id, key, value, langCode)); } diff --git a/test/spec/validations/suspicious_name.js b/test/spec/validations/suspicious_name.js index f7696353d..6acb69390 100644 --- a/test/spec/validations/suspicious_name.js +++ b/test/spec/validations/suspicious_name.js @@ -31,6 +31,10 @@ describe('iD.validations.suspicious_name', function () { iD.fileFetcher.cache().nsi_generics = { genericWords: ['^stores?$'] }; + iD.fileFetcher.cache().preset_presets = { + 'Velero': { tags: { craft: 'sailmaker' }, geometry: ['line'] }, + 'Constructor de barco': { tags: { craft: 'boatbuilder' }, geometry: ['line'] }, + }; }); after(function() { @@ -183,4 +187,29 @@ describe('iD.validations.suspicious_name', function () { done(); }, 20); }); + + it('flags feature with a name that matches the preset name', async () => { + await iD.presetManager.ensureLoaded(true); + createWay({ craft: 'sailmaker', 'name:ca': 'Velero' }); + const validator = iD.validationSuspiciousName(context); + + const issues = validate(validator); + expect(issues).to.have.lengthOf(1); + expect(issues[0].type).to.eql('suspicious_name'); + expect(issues[0].hash).to.eql('name:ca=Velero'); + }); + + it('flags feature with a name that matches the preset name and tag name', async () => { + await iD.presetManager.ensureLoaded(true); + createWay({ craft: 'boatbuilder', 'name:mi': 'boatbuilder', name: 'cOnStRuCtOr de barco' }); + const validator = iD.validationSuspiciousName(context); + + const issues = validate(validator); + expect(issues).to.have.lengthOf(2); + expect(issues[0].type).to.eql('suspicious_name'); + expect(issues[0].hash).to.eql('name:mi=boatbuilder'); + + expect(issues[1].type).to.eql('suspicious_name'); + expect(issues[1].hash).to.eql('name=cOnStRuCtOr de barco'); + }); });