Fixed FELIX-2277 /Allow the user to select display language/
https://issues.apache.org/jira/browse/FELIX-2277

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@984311 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java b/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java
index f179137..4a96fa2 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java
@@ -614,9 +614,37 @@
             pw.println("<div id='technav' class='ui-widget ui-widget-header'>");
             for ( Iterator li = map.values().iterator(); li.hasNext(); )
             {
+                pw.print(' ');
                 pw.println( li.next() );
             }
             pw.println( "</div>" );
+
+        }
+
+        // render lang-box
+        Map langMap = (Map) request.getAttribute(WebConsoleConstants.ATTR_LANG_MAP);
+        if (null != langMap && !langMap.isEmpty())
+        {
+            pw.println("<div id='langSelect'>"); //$NON-NLS-1$
+            pw.println(" <span class='ui-icon ui-icon-comment'>&nbsp;</span>"); //$NON-NLS-1$
+            pw.println(" <span class='flags ui-helper-hidden'>"); //$NON-NLS-1$
+            for (Iterator li = langMap.keySet().iterator(); li.hasNext();)
+            {
+                // <img src="us.gif" alt="en" title="English"/>
+                final Object l = li.next();
+                pw.print("  <img src='"); //$NON-NLS-1$
+                pw.print(appRoot);
+                pw.print("/res/flags/"); //$NON-NLS-1$
+                pw.print(l);
+                pw.print(".gif' alt='"); //$NON-NLS-1$
+                pw.print(l);
+                pw.print("' title='"); //$NON-NLS-1$
+                pw.print(langMap.get(l));
+                pw.println("'/>"); //$NON-NLS-1$
+            }
+
+            pw.println(" </span>"); //$NON-NLS-1$
+            pw.println("</div>"); //$NON-NLS-1$
         }
     }
 
@@ -709,7 +737,7 @@
      * Note: This method is intended to be used internally by the Web Console
      * to update the log level according to the Web Console configuration.
      *
-     * @param logLevel the maximum allowed log level. If message is logged with 
+     * @param logLevel the maximum allowed log level. If message is logged with
      *        lower level it will not be forwarded to the logger.
      */
     public static final void setLogLevel( int logLevel )
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleConstants.java b/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleConstants.java
index daaf9aa..a8590e0 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleConstants.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleConstants.java
@@ -18,6 +18,8 @@
  */
 package org.apache.felix.webconsole;
 
+import java.util.Locale;
+
 /**
  * WebConsoleConstants provides some common constants that are used by plugin
  * developers.
@@ -129,4 +131,24 @@
      * @since 3.0
      */
     static final String ATTR_CONSOLE_VARIABLE_RESOLVER = "felix.webconsole.variable.resolver";
+
+    /**
+     * The name of the request attribute holding the language {@link Map}
+     * for the request (value is "felix.webconsole.langMap").
+     *
+     * This map contains the web console supported languages, which are automatically detected.
+     * The keys of the map are the language codes, like "en", "en_US" .. and so-on.
+     * The value for each key is the locale user-friendly name - exactly the same as
+     * returned by {@link Locale#getDisplayLanguage()}.
+     *
+     * The automatic detection of languages is very simple. It relies on having a
+     * 'res/flags/[lang].gif' file in the bundle. So translators should not only provide
+     * localized l10n/bundle.properties but also a flag image.
+     *
+     * The image should be obtained from http://famfamfam.com/lab/icons/flags/ and eventually
+     * renamed to the correct locale.
+     *
+     * @since 3.1.2
+     */
+    public static final String ATTR_LANG_MAP = "felix.webconsole.langMap"; //$NON-NLS-1$
 }
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
index 3f667d2..a41fa6f 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
@@ -18,11 +18,13 @@
 
 
 import java.io.IOException;
+import java.net.URL;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Dictionary;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.Iterator;
@@ -40,6 +42,7 @@
 import javax.servlet.http.HttpServletRequestWrapper;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.commons.io.FilenameUtils;
 import org.apache.felix.webconsole.AbstractWebConsolePlugin;
 import org.apache.felix.webconsole.BrandingPlugin;
 import org.apache.felix.webconsole.WebConsoleConstants;
@@ -50,6 +53,7 @@
 import org.apache.felix.webconsole.internal.filter.FilteringResponseWrapper;
 import org.apache.felix.webconsole.internal.i18n.ResourceBundleManager;
 import org.apache.felix.webconsole.internal.misc.ConfigurationRender;
+import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.Filter;
@@ -407,6 +411,7 @@
             final Map labelMap = holder.getLocalizedLabelMap( resourceBundleManager, locale );
 
             // the official request attributes
+            request.setAttribute( WebConsoleConstants.ATTR_LANG_MAP, getLangMap() );
             request.setAttribute( WebConsoleConstants.ATTR_LABEL_MAP, labelMap );
             request.setAttribute( WebConsoleConstants.ATTR_APP_ROOT, request.getContextPath() + request.getServletPath() );
             request.setAttribute( WebConsoleConstants.ATTR_PLUGIN_ROOT, request.getContextPath() + request.getServletPath()
@@ -945,6 +950,32 @@
         }
         return stringConfig;
     }
+    
+    private Map langMap;
+
+    private final Map getLangMap()
+    {
+        if (null != langMap) return langMap;
+        final Map map = new HashMap();
+        final Bundle bundle = bundleContext.getBundle();
+        final Enumeration e = bundle.findEntries("res/flags", null, false);
+        while (e != null && e.hasMoreElements())
+        {
+            final URL img = (URL) e.nextElement();
+            final String name = FilenameUtils.getBaseName(img.getFile());
+            try
+            {
+                final String locale = new Locale(name).getDisplayLanguage();
+                map.put(name, null != locale ? locale : name);
+            }
+            catch (Throwable t)
+            {
+                t.printStackTrace();
+                /* ignore invalid locale? */
+            }
+        }
+        return langMap = map;
+    }
 
     static class SecurityProvider implements WebConsoleSecurityProvider {
 
diff --git a/webconsole/src/main/resources/res/flags/bg.gif b/webconsole/src/main/resources/res/flags/bg.gif
new file mode 100644
index 0000000..11cf8ff
--- /dev/null
+++ b/webconsole/src/main/resources/res/flags/bg.gif
Binary files differ
diff --git a/webconsole/src/main/resources/res/flags/de.gif b/webconsole/src/main/resources/res/flags/de.gif
new file mode 100644
index 0000000..75728dd
--- /dev/null
+++ b/webconsole/src/main/resources/res/flags/de.gif
Binary files differ
diff --git a/webconsole/src/main/resources/res/flags/en.gif b/webconsole/src/main/resources/res/flags/en.gif
new file mode 100644
index 0000000..8f198f7
--- /dev/null
+++ b/webconsole/src/main/resources/res/flags/en.gif
Binary files differ
diff --git a/webconsole/src/main/resources/res/lib/support.js b/webconsole/src/main/resources/res/lib/support.js
index 3687e40..2228174 100644
--- a/webconsole/src/main/resources/res/lib/support.js
+++ b/webconsole/src/main/resources/res/lib/support.js
@@ -252,3 +252,15 @@
 	}
 	return element;
 }
+
+// language selection element
+var langSelect = false;
+$(document).ready(function() {
+	langSelect = $('#langSelect').hover( 
+		function() { $(this).find('.flags').show('blind') },
+		function() { $(this).find('.flags').hide('blind') });
+	langSelect.find('.flags img').click(function() {
+		$.cookies.set('felix.webconsole.locale', $(this).attr('alt'));
+		location.reload();
+	});
+});
diff --git a/webconsole/src/main/resources/res/ui/webconsole.css b/webconsole/src/main/resources/res/ui/webconsole.css
index 2219e94..4cf950d 100644
--- a/webconsole/src/main/resources/res/ui/webconsole.css
+++ b/webconsole/src/main/resources/res/ui/webconsole.css
@@ -170,3 +170,6 @@
 	float: left;
 	list-style: none
 }
+/* language selection element */
+#langSelect { position: absolute;	top: 5px; right: 5px }
+#langSelect img   { display: block; padding: 2px 0 }