diff --git a/modules/services/osmose.js b/modules/services/osmose.js index f58d94097..58a777526 100644 --- a/modules/services/osmose.js +++ b/modules/services/osmose.js @@ -230,21 +230,12 @@ export default { return; } - const langs = { [locale]: true }; - - // Need English strings if not already fetched for fallback values - if (locale !== 'en' && !('en' in _stringCache)) { - langs.en = true; - } - - // TODO: Currently all locales are served, in future a param will be available to request specifics - const url = _osmoseUrlRoot + 'items'; + // Osmose API falls back to English strings where untranslated or if locale doesn't exist + const url = _osmoseUrlRoot + 'items?' + utilQsString({ langs: locale }); d3_json(url) .then(data => { - for (let l in langs) { - _stringCache[l] = {}; - } + _stringCache[locale] = {}; for (let i = 0; i < data.categories.length; i++) { let cat = data.categories[i]; @@ -252,22 +243,27 @@ export default { for (let j = 0; j < cat.items.length; j++) { let item = cat.items[j]; + // TODO: Item has 'color' key with hex color code value, automatically style issue markers + // Only need to cache strings for supported error types - // TODO: may be possible to request additional filter by `item` + // TODO: Investigate making multiple requests with filter by `item` and `class` to reduce data further + // See endpoint: https://osmose.openstreetmap.fr/en/api/0.3beta/items/X/class/X?langs=X if (qaServices.osmose.items.indexOf(item.item) !== -1) { for (let k = 0; k < item.class.length; k++) { let { class: cl, item: cat } = item.class[k]; let issueType = `${cat}-${cl}`; + let issueStrings = {}; - for (let l in langs) { - _stringCache[l][issueType] = {}; + // Value of root key will be null if no string exists + // If string exists, value is an object with key 'auto' for string + let { title, detail, trap, fix, example } = item.class[k]; + if (title) issueStrings.title = title.auto; + if (detail) issueStrings.detail = detail.auto; + if (trap) issueStrings.trap = trap.auto; + if (fix) issueStrings.fix = fix.auto; + if (example) issueStrings.example = example.auto; - let issueStrings = _stringCache[l][issueType]; - - // TODO: Only title is currently served, in future description and other strings will be too - let { title: {[l]: title} } = item.class[k]; - if (title) issueStrings.title = title; - } + _stringCache[locale][issueType] = issueStrings; } } } @@ -281,11 +277,8 @@ export default { }, getStrings(issueType, locale=currentLocale) { - const l = (locale in _stringCache) ? _stringCache[locale][issueType] : {}; - const en = ('en' in _stringCache) ? _stringCache.en[issueType] : {}; - - // Fallback to English if string is untranslated - return Object.assign({}, en, l); + // No need to fallback to English, Osmose API handles this for us + return (locale in _stringCache) ? _stringCache[locale][issueType] : {}; }, postUpdate(d, callback) { diff --git a/modules/svg/osmose.js b/modules/svg/osmose.js index 409dfa9d3..898386b09 100644 --- a/modules/svg/osmose.js +++ b/modules/svg/osmose.js @@ -64,8 +64,9 @@ export function svgOsmose(projection, context, dispatch) { // Enable the layer. This shows the errors and transitions them to visible. function layerOn() { // Strings supplied by Osmose fetched before showing layer for first time - // TODO: If layer is toggled quickly multiple requests are sent - // TODO: No error handling in place + // NOTE: Currently no way to change locale in iD at runtime, would need to re-call this method if that's ever implemented + // FIXME: If layer is toggled quickly multiple requests are sent + // FIXME: No error handling in place getService().loadStrings(editOn); drawLayer diff --git a/modules/ui/osmose_details.js b/modules/ui/osmose_details.js index 2f876f00a..788dd4d3e 100644 --- a/modules/ui/osmose_details.js +++ b/modules/ui/osmose_details.js @@ -20,15 +20,15 @@ export function uiOsmoseDetails(context) { // Issue description supplied by Osmose var s = services.osmose.getStrings(d.error_type); - return ('description' in s) ? s.description : unknown; + return ('detail' in s) ? s.detail : unknown; } function osmoseDetails(selection) { var details = selection.selectAll('.error-details') .data( - (_error ? [_error] : []), - function(d) { return d.id + '-' + (d.status || 0); } + _error ? [_error] : [], + d => `${d.id}-${d.status || 0}` ); details.exit() @@ -39,30 +39,31 @@ export function uiOsmoseDetails(context) { .attr('class', 'error-details error-details-container'); - // description var descriptionEnter = detailsEnter .append('div') .attr('class', 'error-details-description'); + // Description descriptionEnter .append('h4') - .text(function() { return t('QA.keepRight.detail_description'); }); + .text(() => t('QA.keepRight.detail_description')); descriptionEnter .append('div') .attr('class', 'error-details-description-text') .html(issueDetail); + // Elements (populated later as data is requested) descriptionEnter .append('h4') .attr('class', 'error-details-subtitle') - .text(function() { return t('QA.osmose.elems_title'); }); + .text(() => t('QA.osmose.elems_title')); var elementList = descriptionEnter .append('ul') .attr('class', 'error-details-elements'); - services.osmose.loadErrorDetail(_error, function(err, d) { + services.osmose.loadErrorDetail(_error, (err, d) => { if (d.elems === undefined) return; elementList.selectAll('.error_entity_link') @@ -71,7 +72,7 @@ export function uiOsmoseDetails(context) { .append('li') .append('a') .attr('class', 'error_entity_link') - .text(function(d) { return d; }) + .text(d => d) .each(function() { var link = d3_select(this); var entityID = this.textContent; @@ -79,11 +80,11 @@ export function uiOsmoseDetails(context) { // Add click handler link - .on('mouseenter', function() { + .on('mouseenter', () => { context.surface().selectAll(utilEntityOrMemberSelector([entityID], context.graph())) .classed('hover', true); }) - .on('mouseleave', function() { + .on('mouseleave', () => { context.surface().selectAll('.hover') .classed('hover', false); }) @@ -123,12 +124,12 @@ export function uiOsmoseDetails(context) { // Things like keys and values are dynamic details const special = { tags: true, values: true, chars: true, sug_tags: true }; - for (let type in special) { + for (const type in special) { if (type in d) { descriptionEnter .append('h4') .attr('class', 'error-details-subtitle') - .text(function() { return t(`QA.osmose.details.${type}`); }); + .text(() => t(`QA.osmose.details.${type}`)); descriptionEnter .append('ul') @@ -137,7 +138,7 @@ export function uiOsmoseDetails(context) { .data(d[type]) .enter() .append('li') - .html(function(d) { return d; }); + .html(d => d); } } @@ -148,7 +149,7 @@ export function uiOsmoseDetails(context) { } - osmoseDetails.error = function(val) { + osmoseDetails.error = (val) => { if (!arguments.length) return _error; _error = val; return osmoseDetails;