[gnome-maps] wikipedia: Find articles in the user's language



commit ec20d9c28582c5a47fe932fec8b9d333feb993c4
Author: James Westman <james flyingpimonster net>
Date:   Mon Aug 10 14:58:25 2020 -0500

    wikipedia: Find articles in the user's language
    
    Using Wikipedia's Language Links feature, we can try to find an article in the
    user's language, even if the place's wikipedia tag is a different language.
    
    This involved refactoring a bit of wikipedia.js.

 src/placeBubble.js |  6 ++--
 src/wikipedia.js   | 92 +++++++++++++++++++++++++++++++++++++++++-------------
 2 files changed, 72 insertions(+), 26 deletions(-)
---
diff --git a/src/placeBubble.js b/src/placeBubble.js
index 8d2a3bbc..2e59fc8f 100644
--- a/src/placeBubble.js
+++ b/src/placeBubble.js
@@ -376,8 +376,6 @@ var PlaceBubble = GObject.registerClass({
     }
 
     _requestWikipedia(wiki) {
-        this._wiki = wiki;
-
         Wikipedia.fetchArticleInfo(wiki,
                                    THUMBNAIL_FETCH_SIZE,
                                    this._onWikiMetadataComplete.bind(this),
@@ -388,10 +386,10 @@ var PlaceBubble = GObject.registerClass({
         this.thumbnail = thumbnail;
     }
 
-    _onWikiMetadataComplete(metadata) {
+    _onWikiMetadataComplete(wiki, metadata) {
         if (metadata.extract) {
             let text = GLib.markup_escape_text(metadata.extract, -1);
-            let link = this._formatWikiLink(this._wiki);
+            let link = this._formatWikiLink(wiki);
 
             /* If the text goes past some number of characters (see
              * wikipedia.js), it is ellipsized with '...'
diff --git a/src/wikipedia.js b/src/wikipedia.js
index cca2ab36..ebe3fa20 100644
--- a/src/wikipedia.js
+++ b/src/wikipedia.js
@@ -58,9 +58,9 @@ function getHtmlEntityEncodedArticle(wiki) {
  *
  * @size is the maximum width of the thumbnail.
  *
- * Calls @metadataCb with an object containing information about the article.
- * For the keys/values of this object, see the relevant MediaWiki API
- * documentation.
+ * Calls @metadataCb with the lang:title pair for the article and an object
+ * containing information about the article. For the keys/values of this
+ * object, see the relevant MediaWiki API documentation.
  *
  * Calls @thumbnailCb with the Gdk.Pixbuf of the icon when successful, otherwise
  * null.
@@ -71,13 +71,16 @@ function fetchArticleInfo(wiki, size, metadataCb, thumbnailCb) {
     let uri = Format.vprintf('https://%s.wikipedia.org/w/api.php', [ lang ]);
     let msg = Soup.form_request_new_from_hash('GET', uri, { action: 'query',
                                                             titles: title,
-                                                            prop: 'extracts|pageimages',
+                                                            prop: 'extracts|pageimages|langlinks',
                                                             format: 'json',
 
                                                             /* Allow redirects, for example if an
                                                                article is renamed. */
                                                             redirects: '1',
 
+                                                            /* Make sure we get all lang links */
+                                                            lllimit: 'max',
+
                                                             /* don't go past first section header */
                                                             exintro: 'yes',
                                                             /* limit the length   */
@@ -88,19 +91,19 @@ function fetchArticleInfo(wiki, size, metadataCb, thumbnailCb) {
                                                             pithumbsize: size + ''});
     let session = _getSoupSession();
     let cachedMetadata = _metadataCache[wiki];
-    let cachedThumbnail = _thumbnailCache[wiki + '/' + size];
 
-    if (cachedMetadata && cachedThumbnail) {
-        metadataCb(cachedMetadata);
-        thumbnailCb(cachedThumbnail);
+    if (cachedMetadata) {
+        _onMetadataFetched(wiki, cachedMetadata, size, metadataCb, thumbnailCb);
         return;
     }
 
     session.queue_message(msg, (session, msg) => {
         if (msg.status_code !== Soup.KnownStatusCode.OK) {
             log("Failed to request Wikipedia metadata: " + msg.reason_phrase);
-            metadataCb({});
-            thumbnailCb(null);
+            metadataCb(null, {});
+            if (thumbnailCb) {
+                thumbnailCb(null);
+            }
             return;
         }
 
@@ -116,30 +119,52 @@ function fetchArticleInfo(wiki, size, metadataCb, thumbnailCb) {
                 let page = pages[pageId];
 
                 _metadataCache[wiki] = page;
-                metadataCb(page);
-
-                let thumbnail = page.thumbnail;
-                if (thumbnail) {
-                    let source = page.thumbnail.source;
-
-                    _fetchThumbnailImage(wiki, size, source, thumbnailCb);
-                } else {
-                    thumbnailCb(null);
-                }
+                _onMetadataFetched(wiki, page, size, metadataCb, thumbnailCb);
                 return;
             }
         } else {
-            metadataCb({});
-            thumbnailCb(null);
+            metadataCb(null, {});
+            if (thumbnailCb) {
+                thumbnailCb(null);
+            }
         }
     });
 }
 
+function _onMetadataFetched(wiki, page, size, metadataCb, thumbnailCb) {
+    /* Try to get a thumbnail *before* following language links--the primary
+       article probably has the best thumbnail image */
+    if (thumbnailCb && page.thumbnail) {
+        let source = page.thumbnail.source;
+
+        _fetchThumbnailImage(wiki, size, source, thumbnailCb);
+        thumbnailCb = null;
+    }
+
+    /* Follow language links if necessary */
+    let langlink = _findLanguageLink(wiki, page);
+    if (langlink) {
+        fetchArticleInfo(langlink, size, metadataCb, thumbnailCb);
+    } else {
+        metadataCb(wiki, page);
+
+        if (thumbnailCb) {
+            thumbnailCb(null);
+        }
+    }
+}
+
 function _fetchThumbnailImage(wiki, size, source, callback) {
     let uri = new Soup.URI(source);
     let msg = new Soup.Message({ method: 'GET', uri: uri });
     let session = _getSoupSession();
 
+    let cachedThumbnail = _thumbnailCache[wiki + '/' + size];
+    if (cachedThumbnail) {
+        callback(cachedThumbnail);
+        return;
+    }
+
     session.queue_message(msg, (session, msg) => {
         if (msg.status_code !== Soup.KnownStatusCode.OK) {
             log("Failed to download thumbnail: " + msg.reason_phrase);
@@ -163,3 +188,26 @@ function _fetchThumbnailImage(wiki, size, source, callback) {
         stream.close(null);
     });
 }
+
+/* Finds the best language to use, based on the language of the original
+   article and the langlinks data from the Wikipedia API.
+
+   Returns a lang:title string if that article should be used, or undefined if
+   the original article should be used. */
+function _findLanguageLink(wiki, page) {
+    let originalLang = getLanguage(wiki);
+    let languages = GLib.get_language_names().map((lang) => lang.split(/[\._\-]/)[0]);
+
+    if (!languages.includes(originalLang)) {
+        let langlinks = {};
+        for (let langlink of (page.langlinks || [])) {
+            langlinks[langlink.lang] = langlink["*"];
+        }
+
+        for (let language of languages) {
+            if (language in langlinks) {
+                return language + ":" + langlinks[language];
+            }
+        }
+    }
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]