modules/services/wikidata.js (167 lines of code) (raw):

import { json as d3_json } from 'd3-fetch'; import { utilQsString } from '@id-sdk/util'; import { localizer } from '../core/localizer'; var apibase = 'https://www.wikidata.org/w/api.php?'; var _wikidataCache = {}; export default { init: function() {}, reset: function() { _wikidataCache = {}; }, // Search for Wikidata items matching the query itemsForSearchQuery: function(query, callback) { if (!query) { if (callback) callback('No query', {}); return; } var lang = this.languagesToQuery()[0]; var url = apibase + utilQsString({ action: 'wbsearchentities', format: 'json', formatversion: 2, search: query, type: 'item', // the language to search language: lang, // the language for the label and description in the result uselang: lang, limit: 10, origin: '*' }); d3_json(url) .then(function(result) { if (result && result.error) { throw new Error(result.error); } if (callback) callback(null, result.search || {}); }) .catch(function(err) { if (callback) callback(err.message, {}); }); }, // Given a Wikipedia language and article title, // return an array of corresponding Wikidata entities. itemsByTitle: function(lang, title, callback) { if (!title) { if (callback) callback('No title', {}); return; } lang = lang || 'en'; var url = apibase + utilQsString({ action: 'wbgetentities', format: 'json', formatversion: 2, sites: lang.replace(/-/g, '_') + 'wiki', titles: title, languages: 'en', // shrink response by filtering to one language origin: '*' }); d3_json(url) .then(function(result) { if (result && result.error) { throw new Error(result.error); } if (callback) callback(null, result.entities || {}); }) .catch(function(err) { if (callback) callback(err.message, {}); }); }, languagesToQuery: function() { return localizer.localeCodes().map(function(code) { return code.toLowerCase(); }).filter(function(code) { // HACK: en-us isn't a wikidata language. We should really be filtering by // the languages known to be supported by wikidata. return code !== 'en-us'; }); }, entityByQID: function(qid, callback) { if (!qid) { callback('No qid', {}); return; } if (_wikidataCache[qid]) { if (callback) callback(null, _wikidataCache[qid]); return; } var langs = this.languagesToQuery(); var url = apibase + utilQsString({ action: 'wbgetentities', format: 'json', formatversion: 2, ids: qid, props: 'labels|descriptions|claims|sitelinks', sitefilter: langs.map(function(d) { return d + 'wiki'; }).join('|'), languages: langs.join('|'), languagefallback: 1, origin: '*' }); d3_json(url) .then(function(result) { if (result && result.error) { throw new Error(result.error); } if (callback) callback(null, result.entities[qid] || {}); }) .catch(function(err) { if (callback) callback(err.message, {}); }); }, // Pass `params` object of the form: // { // qid: 'string' // brand wikidata (e.g. 'Q37158') // } // // Get an result object used to display tag documentation // { // title: 'string', // description: 'string', // editURL: 'string', // imageURL: 'string', // wiki: { title: 'string', text: 'string', url: 'string' } // } // getDocs: function(params, callback) { var langs = this.languagesToQuery(); this.entityByQID(params.qid, function(err, entity) { if (err || !entity) { callback(err || 'No entity'); return; } var i; var description; for (i in langs) { let code = langs[i]; if (entity.descriptions[code] && entity.descriptions[code].language === code) { description = entity.descriptions[code]; break; } } if (!description && Object.values(entity.descriptions).length) description = Object.values(entity.descriptions)[0]; // prepare result var result = { title: entity.id, description: description ? description.value : '', descriptionLocaleCode: description ? description.language : '', editURL: 'https://www.wikidata.org/wiki/' + entity.id }; // add image if (entity.claims) { var imageroot = 'https://commons.wikimedia.org/w/index.php'; var props = ['P154','P18']; // logo image, image var prop, image; for (i = 0; i < props.length; i++) { prop = entity.claims[props[i]]; if (prop && Object.keys(prop).length > 0) { image = prop[Object.keys(prop)[0]].mainsnak.datavalue.value; if (image) { result.imageURL = imageroot + '?' + utilQsString({ title: 'Special:Redirect/file/' + image, width: 400 }); break; } } } } if (entity.sitelinks) { var englishLocale = localizer.languageCode().toLowerCase() === 'en'; // must be one of these that we requested.. for (i = 0; i < langs.length; i++) { // check each, in order of preference var w = langs[i] + 'wiki'; if (entity.sitelinks[w]) { var title = entity.sitelinks[w].title; var tKey = 'inspector.wiki_reference'; if (!englishLocale && langs[i] === 'en') { // user's locale isn't English but tKey = 'inspector.wiki_en_reference'; // we are sending them to enwiki anyway.. } result.wiki = { title: title, text: tKey, url: 'https://' + langs[i] + '.wikipedia.org/wiki/' + title.replace(/ /g, '_') }; break; } } } callback(null, result); }); } };