diff --git a/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java b/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java
index e56b88e5b6cdda9921a4818f8605cd33a21e7ef0..611f7a5b9492ead2cdd4d6cdc88b6ca76abe0009 100644
--- a/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java
+++ b/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java
@@ -70,6 +70,9 @@ class NewsFetcher extends UpdateRunner {
     private long _newLastModified;
     private final File _newsFile;
     private final File _tempFile;
+    private final long _timeout;
+    private final boolean _showStatus;
+    private String _failMsg;
     /** is the news newer */
     private boolean _isNewer;
     private boolean _success;
@@ -80,14 +83,28 @@ class NewsFetcher extends UpdateRunner {
     static final String PROP_BLOCKLIST_TIME = "router.blocklistVersion";
     private static final String BLOCKLIST_DIR = "docs/feed/blocklist";
     private static final String BLOCKLIST_FILE = "blocklist.txt";
+    private static final long DEFAULT_TIMEOUT = 60*1000;
     
     public NewsFetcher(RouterContext ctx, ConsoleUpdateManager mgr, List<URI> uris) { 
+        this(ctx, mgr, uris, DEFAULT_TIMEOUT);
+    }
+
+    /**
+     *  @param timeout if less than 60 seconds, we assume this was manually initiated,
+     *                 and we will log status to the sidebar
+     *  @since 0.9.62
+     */
+    public NewsFetcher(RouterContext ctx, ConsoleUpdateManager mgr, List<URI> uris, long timeout) { 
         super(ctx, mgr, NEWS, uris);
         _newsFile = new File(ctx.getRouterDir(), NewsHelper.NEWS_FILE);
         _tempFile = new File(ctx.getTempDir(), "tmp-" + ctx.random().nextLong() + TEMP_NEWS_FILE);
-        long lastMod = NewsHelper.lastUpdated(ctx);
-        if (lastMod > 0)
-            _lastModified = RFC822Date.to822Date(lastMod);
+        _timeout = timeout;
+        _showStatus = timeout < DEFAULT_TIMEOUT;
+        if (!langChanged()) {
+            long lastMod = NewsHelper.lastUpdated(ctx);
+            if (lastMod > 0)
+                _lastModified = RFC822Date.to822Date(lastMod);
+        }
     }
 
     @Override
@@ -140,7 +157,7 @@ class NewsFetcher extends UpdateRunner {
                 long start = _context.clock().now();
                 // will be adjusted in headerReceived() below
                 _newLastModified = start;
-                if (get.fetch()) {
+                if (get.fetch(_timeout)) {
                     int status = get.getStatusCode();
                     if (status == 200 || status == 304) {
                         Map<String, String> opts = new HashMap<String, String>(3);
@@ -148,12 +165,39 @@ class NewsFetcher extends UpdateRunner {
                         if (status == 200 && _isNewer) {
                             String lastMod = Long.toString(_newLastModified);
                             opts.put(NewsHelper.PROP_LAST_UPDATED, lastMod);
+                            String lang = Translate.getLanguage(_context);
+                            opts.put(NewsHelper.PROP_LAST_LANG, lang);
                             if (_gotNewEntry)
                                 opts.put(NewsHelper.PROP_LAST_NEW_ENTRY, lastMod);
                         }
                         _context.router().saveConfig(opts, null);
+                        if (_failMsg != null) {
+                            // from checkForUpdates()
+                            _mgr.notifyComplete(this, "<b>" + _failMsg + "</b>");
+                        } else if (_showStatus) {
+                            if (status == 200)
+                                _mgr.notifyComplete(this, "News updated from " + _currentURI.getHost());
+                            else
+                                _mgr.notifyComplete(this, "No new news available from " + _currentURI.getHost());
+                        }
                         return;
                     }
+                } else {
+                    int status = get.getStatusCode();
+                    String msg;
+                    if (status == 504 || status <= 0)
+                        msg = "Unable to connect to news server " + _currentURI.getHost();
+                    else if (status == 500)
+                        msg = "News server " + _currentURI.getHost() + " not found in address book";
+                    else if (status == 404)
+                        msg = "News file not found on news server at " + newsURL;
+                    else
+                        msg = status + " " + DataHelper.stripHTML(get.getStatusText());
+                    // only display if manually initiated
+                    if (_showStatus)
+                        updateStatus("<b>" + msg + "</b>");
+                    if (_log.shouldWarn())
+                        _log.warn(msg);
                 }
             } catch (Throwable t) {
                 _log.error("Error fetching the news", t);
@@ -194,6 +238,17 @@ class NewsFetcher extends UpdateRunner {
             return uri;
         }
     }
+
+    /**
+     *  @since 0.9.62
+     */
+    private boolean langChanged() {
+        String old = _context.getProperty(NewsHelper.PROP_LAST_LANG);
+        if (old == null)
+            return false;
+        String lang = Translate.getLanguage(_context);
+        return !lang.equals(old);
+    }
     
     // Fake XML parsing
     // Line must contain this, and full entry must be on one line
@@ -213,6 +268,7 @@ class NewsFetcher extends UpdateRunner {
     // unused
     //private static final String I2P_SUD_KEY = "sudi2p";
     //private static final String I2P_SU2_KEY = "su2i2p";
+
     /**
      *  @since 0.9.52
      */
@@ -325,6 +381,7 @@ class NewsFetcher extends UpdateRunner {
         } catch (IOException ioe) {
             if (_log.shouldLog(Log.WARN))
                 _log.warn("Error checking the news for an update", ioe);
+            _failMsg = "Error checking the news for an update: " + ioe;
             return;
         } finally {
             if (in != null) try { in.close(); } catch (IOException ioe) {}
@@ -486,9 +543,38 @@ class NewsFetcher extends UpdateRunner {
         _success = true;
     }
 
-    /** override to prevent status update */
+    /**
+     * override for status update
+     * @since 0.9.62
+     */
     @Override
-    public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {}
+    public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {
+        // only display if manually initiated
+        if (_showStatus) {
+            String msg = "Unable to connect to news server " + url + ": " + DataHelper.stripHTML(cause.toString());
+            updateStatus("<b>" + msg + "</b>");
+            if (_log.shouldWarn())
+                _log.warn(msg);
+        }
+        // update manager will also log
+        _mgr.notifyAttemptFailed(this, url, null);
+    }
+
+    /**
+     * override for status update
+     */
+    @Override
+    public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {
+        // only display if manually initiated
+        if (_showStatus) {
+            String msg = "Failed downloading news from " + url;
+            updateStatus("<b>" + msg + "</b>");
+            if (_log.shouldWarn())
+                _log.warn(msg);
+        }
+        // update manager will also log
+        _mgr.notifyAttemptFailed(this, url, null);
+    }
 
     /**
      *  Process the fetched su3 news file _tempFile.
diff --git a/apps/routerconsole/java/src/net/i2p/router/update/NewsHandler.java b/apps/routerconsole/java/src/net/i2p/router/update/NewsHandler.java
index 1c5fbe68274a0666f124dded345d8e49adee9a7f..a6a6cca9f16cd382ce7330800984bd39ee8ac8cc 100644
--- a/apps/routerconsole/java/src/net/i2p/router/update/NewsHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/update/NewsHandler.java
@@ -67,7 +67,7 @@ public class NewsHandler extends UpdateHandler implements Checker {
             //updateSources.add(new URI(BACKUP_NEWS_URL));
             updateSources.add(new URI(_context.getProperty(PROP_BACKUP_NEWS_URL_SU3, DEFAULT_BACKUP_NEWS_URL_SU3)));
         } catch (URISyntaxException use) {}
-        UpdateRunner update = new NewsFetcher(_context, _mgr, updateSources);
+        UpdateRunner update = new NewsFetcher(_context, _mgr, updateSources, maxTime);
         return update;
     }
 
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NewsHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/NewsHelper.java
index 1e71d869056bd3cef1ca7e09c498a54515e95365..54f29a2b5376dbfe9e68b33e3f0989b1fbf5115c 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/NewsHelper.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/NewsHelper.java
@@ -27,6 +27,8 @@ public class NewsHelper extends ContentHelper {
     public static final String PROP_LAST_UPDATED = "routerconsole.newsLastUpdated";
     /** @since 0.9.55 */
     public static final String PROP_LAST_NEW_ENTRY = "routerconsole.newsLastNewEntry";
+    /** @since 0.9.62 */
+    public static final String PROP_LAST_LANG = "routerconsole.newsLastLanguage";
     /**
      * Default true
      * @since 0.9.21