From 07753f0feaf23c21a62334f22b0cb05cac4b8d84 Mon Sep 17 00:00:00 2001
From: "mgiuca@chromium.org"
 <mgiuca@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Tue, 5 Feb 2013 07:52:59 +0000
Subject: App shortcut creation on Linux now removes localized versions of the
 Name key.

Previously, if the Chrome .desktop file had a localized string for the app name,
and the user was in a non-US locale, the localized string would be copied
(unmodified) to the app shortcut, and the app name would display as a localized
version "Google Chrome" or "Chromium Browser" instead of the actual app name.

BUG=173324


Review URL: https://chromiumcodereview.appspot.com/12114044

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@180634 0039d316-1c4b-4281-b951-d872f2087c98
---
 chrome/browser/shell_integration_linux.cc    | 17 ++++++
 chrome/browser/shell_integration_unittest.cc | 82 +++++++++++++++++++++++-----
 2 files changed, 84 insertions(+), 15 deletions(-)

diff --git a/chrome/browser/shell_integration_linux.cc b/chrome/browser/shell_integration_linux.cc
index 745d631..41cde76 100644
--- a/chrome/browser/shell_integration_linux.cc
+++ b/chrome/browser/shell_integration_linux.cc
@@ -252,6 +252,9 @@ const char kXdgSettings[] = "xdg-settings";
 const char kXdgSettingsDefaultBrowser[] = "default-web-browser";
 const char kXdgSettingsDefaultSchemeHandler[] = "default-url-scheme-handler";
 
+// Regex to match a localized key name such as "Name[en_AU]".
+const char kLocalizedKeyRegex[] = "^[A-Za-z0-9\\-]+\\[[^\\]]*\\]$";
+
 }  // namespace
 
 namespace {
@@ -567,6 +570,20 @@ std::string GetDesktopFileContents(
        ++current_key) {
     g_key_file_remove_key(key_file, kDesktopEntry, *current_key, NULL);
   }
+  // Remove all localized keys.
+  GRegex* localized_key_regex = g_regex_new(kLocalizedKeyRegex,
+                                            static_cast<GRegexCompileFlags>(0),
+                                            static_cast<GRegexMatchFlags>(0),
+                                            NULL);
+  gchar** keys = g_key_file_get_keys(key_file, kDesktopEntry, NULL, NULL);
+  for (gchar** keys_ptr = keys; *keys_ptr; ++keys_ptr) {
+    if (g_regex_match(localized_key_regex, *keys_ptr,
+                      static_cast<GRegexMatchFlags>(0), NULL)) {
+      g_key_file_remove_key(key_file, kDesktopEntry, *keys_ptr, NULL);
+    }
+  }
+  g_strfreev(keys);
+  g_regex_unref(localized_key_regex);
 
   // Set the "Name" key.
   std::string final_title = UTF16ToUTF8(title);
diff --git a/chrome/browser/shell_integration_unittest.cc b/chrome/browser/shell_integration_unittest.cc
index 7179cbc..8dbb3e7 100644
--- a/chrome/browser/shell_integration_unittest.cc
+++ b/chrome/browser/shell_integration_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/shell_integration.h"
 
+#include <cstdlib>
 #include <map>
 
 #include "base/file_path.h"
@@ -65,6 +66,43 @@ class MockEnvironment : public base::Environment {
   DISALLOW_COPY_AND_ASSIGN(MockEnvironment);
 };
 
+// Allows you to change the real environment, but reverts changes upon
+// destruction.
+class ScopedEnvironment {
+ public:
+  ScopedEnvironment() {}
+
+  ~ScopedEnvironment() {
+    for (std::map<std::string, std::string>::const_iterator
+         it = old_variables_.begin(); it != old_variables_.end(); ++it) {
+      if (it->second.empty()) {
+        unsetenv(it->first.c_str());
+      } else {
+        setenv(it->first.c_str(), it->second.c_str(), 1);
+      }
+    }
+  }
+
+  void Set(const std::string& name, const std::string& value) {
+    if (!ContainsKey(old_variables_, name)) {
+      const char* value = getenv(name.c_str());
+      if (value != NULL) {
+        old_variables_[name] = value;
+      } else {
+        old_variables_[name] = std::string();
+      }
+    }
+    setenv(name.c_str(), value.c_str(), 1);
+  }
+
+ private:
+  // Map from name to original value, or the empty string if there was no
+  // previous value.
+  std::map<std::string, std::string> old_variables_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedEnvironment);
+};
+
 }  // namespace
 
 TEST(ShellIntegrationTest, GetDesktopShortcutTemplate) {
@@ -179,6 +217,7 @@ TEST(ShellIntegrationTest, GetDesktopFileContents) {
       "Version=1.0\n"
       "Encoding=UTF-8\n"
       "Name=Google Chrome\n"
+      "GenericName=Web Browser\n"
       "Comment=The web browser from Google\n"
       "Exec=/opt/google/chrome/google-chrome %U\n"
       "Terminal=false\n"
@@ -204,8 +243,8 @@ TEST(ShellIntegrationTest, GetDesktopFileContents) {
       "Type=Application\n"
       "Categories=Application;Network;WebBrowser;\n"
 #if !defined(USE_AURA)
-      // Aura Chrome creates browser window in a single X11 window, so
-      // WMClass does not matter.
+      // Aura Chrome does not (yet) set WMClass, so we only expect
+      // StartupWMClass on non-Aura builds.
       "StartupWMClass=gmail.com\n"
 #endif
     },
@@ -226,20 +265,26 @@ TEST(ShellIntegrationTest, GetDesktopFileContents) {
       "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
       "Icon=chrome-http__gmail.com\n"
 #if !defined(USE_AURA)
-      // Aura Chrome creates browser window in a single X11 window, so
-      // WMClass does not matter.
+      // Aura Chrome does not (yet) set WMClass, so we only expect
+      // StartupWMClass on non-Aura builds.
       "StartupWMClass=gmail.com\n"
 #endif
     },
 
-    // Make sure i18n-ed comments are removed.
+    // Make sure i18n-ed names and other fields are removed.
     { "http://gmail.com",
       "GMail",
       "chrome-http__gmail.com",
 
       "[Desktop Entry]\n"
       "Name=Google Chrome\n"
+      "Name[en_AU]=Google Chrome\n"
+      "Name[pl]=Google Chrome\n"
+      "GenericName=Web Browser\n"
+      "GenericName[en_AU]=Web Browser\n"
+      "GenericName[pl]=Navegador Web\n"
       "Exec=/opt/google/chrome/google-chrome %U\n"
+      "Comment[en_AU]=Some comment.\n"
       "Comment[pl]=Jakis komentarz.\n",
 
       "#!/usr/bin/env xdg-open\n"
@@ -248,8 +293,8 @@ TEST(ShellIntegrationTest, GetDesktopFileContents) {
       "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
       "Icon=chrome-http__gmail.com\n"
 #if !defined(USE_AURA)
-      // Aura Chrome creates browser window in a single X11 window, so
-      // WMClass does not matter.
+      // Aura Chrome does not (yet) set WMClass, so we only expect
+      // StartupWMClass on non-Aura builds.
       "StartupWMClass=gmail.com\n"
 #endif
     },
@@ -271,8 +316,8 @@ TEST(ShellIntegrationTest, GetDesktopFileContents) {
       "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
       "Icon=/opt/google/chrome/product_logo_48.png\n"
 #if !defined(USE_AURA)
-      // Aura Chrome creates browser window in a single X11 window, so
-      // WMClass does not matter.
+      // Aura Chrome does not (yet) set WMClass, so we only expect
+      // StartupWMClass on non-Aura builds.
       "StartupWMClass=gmail.com\n"
 #endif
     },
@@ -293,8 +338,8 @@ TEST(ShellIntegrationTest, GetDesktopFileContents) {
       "--app=http://evil.com/evil%20--join-the-b0tnet\n"
       "Icon=chrome-http__evil.com_evil\n"
 #if !defined(USE_AURA)
-      // Aura Chrome creates browser window in a single X11 window, so
-      // WMClass does not matter.
+      // Aura Chrome does not (yet) set WMClass, so we only expect
+      // StartupWMClass on non-Aura builds.
       "StartupWMClass=evil.com__evil%20--join-the-b0tnet\n"
 #endif
     },
@@ -317,8 +362,8 @@ TEST(ShellIntegrationTest, GetDesktopFileContents) {
       "-rf%20\\\\$HOME%20%3Eownz0red\"\n"
       "Icon=chrome-http__evil.com_evil\n"
 #if !defined(USE_AURA)
-      // Aura Chrome creates browser window in a single X11 window, so
-      // WMClass does not matter.
+      // Aura Chrome does not (yet) set WMClass, so we only expect
+      // StartupWMClass on non-Aura builds.
       "StartupWMClass=evil.com__evil;%20rm%20-rf%20_;%20%22;%20"
       "rm%20-rf%20$HOME%20%3Eownz0red\n"
 #endif
@@ -339,13 +384,20 @@ TEST(ShellIntegrationTest, GetDesktopFileContents) {
       "%60%20%3E/dev/null\n"
       "Icon=chrome-http__evil.com_evil\n"
 #if !defined(USE_AURA)
-      // Aura Chrome creates browser window in a single X11 window, so
-      // WMClass does not matter.
+      // Aura Chrome does not (yet) set WMClass, so we only expect
+      // StartupWMClass on non-Aura builds.
       "StartupWMClass=evil.com__evil%20%7C%20cat%20%60echo%20ownz0red"
       "%60%20%3E_dev_null\n"
 #endif
     },
   };
+
+  // Set the language to en_AU. This causes glib to copy the en_AU localized
+  // strings into the shortcut file. (We want to test that they are removed.)
+  ScopedEnvironment env;
+  env.Set("LC_ALL", "en_AU.UTF-8");
+  env.Set("LANGUAGE", "en_AU.UTF-8");
+
   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); i++) {
     SCOPED_TRACE(i);
     EXPECT_EQ(
-- 
cgit v1.1