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

[vidalia-svn] r3220: Support changing UI languages without restarting Vidalia. Th (in vidalia/trunk/src/vidalia: . bwgraph config help/browser log network)



Author: edmanm
Date: 2008-10-12 20:11:28 -0400 (Sun, 12 Oct 2008)
New Revision: 3220

Modified:
   vidalia/trunk/src/vidalia/bwgraph/bwgraph.cpp
   vidalia/trunk/src/vidalia/bwgraph/bwgraph.h
   vidalia/trunk/src/vidalia/config/advancedpage.cpp
   vidalia/trunk/src/vidalia/config/advancedpage.h
   vidalia/trunk/src/vidalia/config/appearancepage.cpp
   vidalia/trunk/src/vidalia/config/appearancepage.h
   vidalia/trunk/src/vidalia/config/configdialog.cpp
   vidalia/trunk/src/vidalia/config/configdialog.h
   vidalia/trunk/src/vidalia/config/configpage.h
   vidalia/trunk/src/vidalia/config/generalpage.cpp
   vidalia/trunk/src/vidalia/config/generalpage.h
   vidalia/trunk/src/vidalia/config/networkpage.cpp
   vidalia/trunk/src/vidalia/config/networkpage.h
   vidalia/trunk/src/vidalia/config/serverpage.cpp
   vidalia/trunk/src/vidalia/config/serverpage.h
   vidalia/trunk/src/vidalia/config/servicepage.cpp
   vidalia/trunk/src/vidalia/config/servicepage.h
   vidalia/trunk/src/vidalia/help/browser/helpbrowser.cpp
   vidalia/trunk/src/vidalia/help/browser/helpbrowser.h
   vidalia/trunk/src/vidalia/languagesupport.cpp
   vidalia/trunk/src/vidalia/languagesupport.h
   vidalia/trunk/src/vidalia/log/messagelog.cpp
   vidalia/trunk/src/vidalia/log/messagelog.h
   vidalia/trunk/src/vidalia/main.cpp
   vidalia/trunk/src/vidalia/mainwindow.cpp
   vidalia/trunk/src/vidalia/mainwindow.h
   vidalia/trunk/src/vidalia/network/netviewer.cpp
   vidalia/trunk/src/vidalia/network/netviewer.h
   vidalia/trunk/src/vidalia/vidalia.cpp
   vidalia/trunk/src/vidalia/vidalia.h
   vidalia/trunk/src/vidalia/vidaliawindow.cpp
   vidalia/trunk/src/vidalia/vidaliawindow.h
Log:
Support changing UI languages without restarting Vidalia. Those playing along
at home get one Vidalia point for finding widgets that I missed that don't get
retranslated.


Modified: vidalia/trunk/src/vidalia/bwgraph/bwgraph.cpp
===================================================================
--- vidalia/trunk/src/vidalia/bwgraph/bwgraph.cpp	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/bwgraph/bwgraph.cpp	2008-10-13 00:11:28 UTC (rev 3220)
@@ -77,6 +77,13 @@
 #endif
 }
 
+/** Called when the user changes the UI translation. */
+void
+BandwidthGraph::retranslateUi()
+{
+  ui.retranslateUi(this);
+}
+
 /** Custom event handler. Checks if the event is a bandwidth update event. If it
  * is, it will add the data point to the history and updates the graph. */
 void

Modified: vidalia/trunk/src/vidalia/bwgraph/bwgraph.h
===================================================================
--- vidalia/trunk/src/vidalia/bwgraph/bwgraph.h	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/bwgraph/bwgraph.h	2008-10-13 00:11:28 UTC (rev 3220)
@@ -45,7 +45,9 @@
 protected:
   /** Called to deliver a bandwidth update event from Tor. */
   void customEvent(QEvent *event);
-  
+  /** Called when the user changes the UI translation. */
+  virtual void retranslateUi();
+
 private slots:
   /** Adds new data to the graph */
   void updateGraph(quint64 bytesRead, quint64 bytesWritten);

Modified: vidalia/trunk/src/vidalia/config/advancedpage.cpp
===================================================================
--- vidalia/trunk/src/vidalia/config/advancedpage.cpp	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/config/advancedpage.cpp	2008-10-13 00:11:28 UTC (rev 3220)
@@ -31,7 +31,7 @@
 
 /** Constructor */
 AdvancedPage::AdvancedPage(QWidget *parent)
-: ConfigPage(parent, tr("Advanced"))
+: ConfigPage(parent, "Advanced")
 {
   /* Invoke the Qt Designer generated object setup routine */
   ui.setupUi(this);
@@ -67,6 +67,13 @@
   delete _settings;
 }
 
+/** Called when the user changes the UI translation. */
+void
+AdvancedPage::retranslateUi()
+{
+  ui.retranslateUi(this);
+}
+
 /** Applies the network configuration settings to Tor. Returns true if the
  * settings were applied successfully. Otherwise, <b>errmsg</b> is set
  * and false is returned. */

Modified: vidalia/trunk/src/vidalia/config/advancedpage.h
===================================================================
--- vidalia/trunk/src/vidalia/config/advancedpage.h	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/config/advancedpage.h	2008-10-13 00:11:28 UTC (rev 3220)
@@ -48,6 +48,8 @@
   /** Returns true if the user has changed their advanced Tor settings since
    * the last time they were applied to Tor. */
   bool changedSinceLastApply();
+  /** Called when the user changes the UI translation. */
+  virtual void retranslateUi();
 
 private slots:
   /** Called when the user selects a different authentication method from the

Modified: vidalia/trunk/src/vidalia/config/appearancepage.cpp
===================================================================
--- vidalia/trunk/src/vidalia/config/appearancepage.cpp	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/config/appearancepage.cpp	2008-10-13 00:11:28 UTC (rev 3220)
@@ -15,12 +15,13 @@
 */
 
 #include <vidalia.h>
+#include <vmessagebox.h>
 #include "appearancepage.h"
 
 
 /** Default Constructor */
 AppearancePage::AppearancePage(QWidget *parent)
-: ConfigPage(parent, tr("Appearance"))
+  : ConfigPage(parent, "Appearance")
 {
   /* Invoke Designer-generated object setup routine */
   ui.setupUi(this);
@@ -44,19 +45,34 @@
   delete _settings;
 }
 
+/** Called when the user changes the UI translation. */
+void
+AppearancePage::retranslateUi()
+{
+  ui.retranslateUi(this);
+}
+
 /** Saves the changes on this page */
 bool
 AppearancePage::save(QString &errmsg)
 {
-  Q_UNUSED(errmsg);
+  QString prevLanguage = _settings->getLanguageCode();
   QString languageCode =
     LanguageSupport::languageCode(ui.cmboLanguage->currentText());
-  
-  _settings->setLanguageCode(languageCode);
+
+  /* Set the new language */
+  if (prevLanguage != languageCode) {
+    if (! Vidalia::retranslateUi(languageCode)) {
+      errmsg = tr("Vidalia was unable to load the selected "
+                  "language translation.");
+      return false;
+    }
+    _settings->setLanguageCode(languageCode);
+  }
+
+  /* Set the new style */
+  Vidalia::setStyle(ui.cmboStyle->currentText());
   _settings->setInterfaceStyle(ui.cmboStyle->currentText());
- 
-  /* Set to new style */
-  Vidalia::setStyle(ui.cmboStyle->currentText());
   return true;
 }
   

Modified: vidalia/trunk/src/vidalia/config/appearancepage.h
===================================================================
--- vidalia/trunk/src/vidalia/config/appearancepage.h	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/config/appearancepage.h	2008-10-13 00:11:28 UTC (rev 3220)
@@ -39,7 +39,9 @@
   bool save(QString &errmsg);
   /** Loads the settings for this page */
   void load();
-  
+  /** Called when the user changes the UI translation. */
+  virtual void retranslateUi();
+
 private:
   /** A VidaliaSettings object used for saving/loading settings */
   VidaliaSettings* _settings;

Modified: vidalia/trunk/src/vidalia/config/configdialog.cpp
===================================================================
--- vidalia/trunk/src/vidalia/config/configdialog.cpp	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/config/configdialog.cpp	2008-10-13 00:11:28 UTC (rev 3220)
@@ -42,6 +42,7 @@
 #define IMAGE_HELP          ":/images/32x32/system-help.png"
 #define IMAGE_SERVICE       ":/images/32x32/services.png"
 
+
 /** Constructor */
 ConfigDialog::ConfigDialog(QWidget* parent)
 : VidaliaWindow("ConfigDialog", parent)
@@ -73,27 +74,27 @@
   QActionGroup *grp = new QActionGroup(this);
   ui.stackPages->add(new GeneralPage(ui.stackPages),
                      createPageAction(QIcon(IMAGE_GENERAL),
-                                      tr("General"), grp));
-  
+                                      tr("General"), "General", grp));
+
   ui.stackPages->add(new NetworkPage(ui.stackPages),
                      createPageAction(QIcon(IMAGE_NETWORK),
-                                      tr("Network"), grp));
-  
+                                      tr("Network"), "Network", grp));
+
   ui.stackPages->add(new ServerPage(ui.stackPages),
                      createPageAction(QIcon(IMAGE_SERVER),
-                                      tr("Sharing"), grp));
-  
+                                      tr("Sharing"), "Sharing", grp));
+
   ui.stackPages->add(new ServicePage(ui.stackPages),
                      createPageAction(QIcon(IMAGE_SERVICE),
-                                      tr("Services"), grp));
+                                      tr("Services"), "Services", grp));
 
   ui.stackPages->add(new AppearancePage(ui.stackPages),
                      createPageAction(QIcon(IMAGE_APPEARANCE),
-                                      tr("Appearance"), grp));
-  
+                                      tr("Appearance"), "Appearance", grp));
+
   ui.stackPages->add(new AdvancedPage(ui.stackPages),
                      createPageAction(QIcon(IMAGE_ADVANCED),
-                                      tr("Advanced"), grp));
+                                      tr("Advanced"), "Advanced", grp));
 
   foreach (ConfigPage *page, ui.stackPages->pages()) {
     connect(page, SIGNAL(helpRequested(QString)),
@@ -108,6 +109,7 @@
   
   /* Create and bind the Help button */
   QAction *helpAct = new QAction(QIcon(IMAGE_HELP), tr("Help"), ui.toolBar);
+  helpAct->setData("Help");
   addAction(helpAct, SLOT(help()));
 
   /* Select the first action */
@@ -122,9 +124,11 @@
 
 /** Creates a new action associated with a config page. */
 QAction*
-ConfigDialog::createPageAction(QIcon img, QString text, QActionGroup *group)
+ConfigDialog::createPageAction(const QIcon &img, const QString &text, 
+                               const QString &data, QActionGroup *group)
 {
   QAction *action = new QAction(img, text, group);
+  action->setData(data);
   action->setCheckable(true);
   return action;
 }
@@ -150,6 +154,19 @@
   ui.stackPages->setCurrentIndex((int)page);
 }
 
+/** Called when the user changes the UI translation. */
+void
+ConfigDialog::retranslateUi()
+{
+  ui.retranslateUi(this);
+  foreach (ConfigPage *page, ui.stackPages->pages()) {
+    page->retranslateUi();
+  }
+  foreach (QAction *action, ui.toolBar->actions()) {
+    action->setText(tr(qPrintable(action->data().toString()), "ConfigDialog"));
+  }
+}
+
 /** Loads the saved ConfigDialog settings. */
 void
 ConfigDialog::loadSettings()
@@ -177,7 +194,7 @@
       VMessageBox::warning(this, 
         tr("Error Saving Settings"), 
         p(tr("Vidalia was unable to save your %1 settings.")
-             .arg(page->title())) + p(errmsg),
+             .arg(tr(qPrintable(page->title()), "ConfigDialog"))) + p(errmsg),
         VMessageBox::Ok);
 
       /* Don't process the rest of the pages */

Modified: vidalia/trunk/src/vidalia/config/configdialog.h
===================================================================
--- vidalia/trunk/src/vidalia/config/configdialog.h	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/config/configdialog.h	2008-10-13 00:11:28 UTC (rev 3220)
@@ -53,6 +53,10 @@
   /** Shows the config dialog with focus set to the given page. */
   void showWindow(Page page = General);
 
+protected:
+  /** Called when the user changes the UI translation. */
+  virtual void retranslateUi();
+
 private slots:
   /** Called when user clicks "Save Settings". Saves their settings to
    * Vidalia's configuration file. */
@@ -75,7 +79,8 @@
   /** Loads the current configuration settings */
   void loadSettings();
   /** Creates a new action for a config page. */
-  QAction* createPageAction(QIcon img, QString text, QActionGroup *group);
+  QAction* createPageAction(const QIcon &img, const QString &text,
+                            const QString &data, QActionGroup *group);
   /** Adds a new action to the toolbar. */
   void addAction(QAction *action, const char *slot = 0);
 

Modified: vidalia/trunk/src/vidalia/config/configpage.h
===================================================================
--- vidalia/trunk/src/vidalia/config/configpage.h	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/config/configpage.h	2008-10-13 00:11:28 UTC (rev 3220)
@@ -55,6 +55,8 @@
   /** Subclassed pages can overload this method to revert any cancelled
    * settings. */
   virtual void revert() {}
+  
+  virtual void retranslateUi() {}
 
 signals:
   /** Signal emitted when a ConfigPage requests help information on a given

Modified: vidalia/trunk/src/vidalia/config/generalpage.cpp
===================================================================
--- vidalia/trunk/src/vidalia/config/generalpage.cpp	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/config/generalpage.cpp	2008-10-13 00:11:28 UTC (rev 3220)
@@ -21,7 +21,7 @@
 
 /** Constructor */
 GeneralPage::GeneralPage(QWidget *parent)
-: ConfigPage(parent, tr("General"))
+: ConfigPage(parent, "General")
 {
   /* Invoke the Qt Designer generated object setup routine */
   ui.setupUi(this);
@@ -53,6 +53,13 @@
   delete _torSettings;
 }
 
+/** Called when the user changes the UI translation. */
+void
+GeneralPage::retranslateUi()
+{
+  ui.retranslateUi(this);
+}
+
 /** Displays a file dialog allowing the user to browse for an executable
  * file. <b>caption</b> will be displayed in the dialog's title bar and
  * <b>file</b>, if specified, is the default file selected in the dialog.

Modified: vidalia/trunk/src/vidalia/config/generalpage.h
===================================================================
--- vidalia/trunk/src/vidalia/config/generalpage.h	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/config/generalpage.h	2008-10-13 00:11:28 UTC (rev 3220)
@@ -37,6 +37,8 @@
   bool save(QString &errmsg);
   /** Loads the settings for this page */
   void load();
+  /** Called when the user changes the UI translation. */
+  virtual void retranslateUi();
 
 private slots:
   /** Open a QFileDialog to browse for a Tor executable file. */

Modified: vidalia/trunk/src/vidalia/config/networkpage.cpp
===================================================================
--- vidalia/trunk/src/vidalia/config/networkpage.cpp	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/config/networkpage.cpp	2008-10-13 00:11:28 UTC (rev 3220)
@@ -31,7 +31,7 @@
 
 /** Constructor */
 NetworkPage::NetworkPage(QWidget *parent)
-: ConfigPage(parent, tr("Network"))
+: ConfigPage(parent, "Network")
 {
   /* Invoke the Qt Designer generated object setup routine */
   ui.setupUi(this);
@@ -69,6 +69,13 @@
 #endif
 }
 
+/** Called when the user changes the UI translation. */
+void
+NetworkPage::retranslateUi()
+{
+  ui.retranslateUi(this);
+}
+
 /** Applies the network configuration settings to Tor. Returns true if the   *
  * settings were applied successfully. Otherwise, <b>errmsg</b> is set and   *
  * false is returned. */

Modified: vidalia/trunk/src/vidalia/config/networkpage.h
===================================================================
--- vidalia/trunk/src/vidalia/config/networkpage.h	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/config/networkpage.h	2008-10-13 00:11:28 UTC (rev 3220)
@@ -47,6 +47,8 @@
   /** Returns true if the user has changed their server settings since the
    * last time they were applied to Tor. */
   bool changedSinceLastApply();
+  /** Called when the user changes the UI translation. */
+  virtual void retranslateUi();
 
 private slots:
   /** Adds a bridge to the bridge list box. */

Modified: vidalia/trunk/src/vidalia/config/serverpage.cpp
===================================================================
--- vidalia/trunk/src/vidalia/config/serverpage.cpp	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/config/serverpage.cpp	2008-10-13 00:11:28 UTC (rev 3220)
@@ -65,7 +65,7 @@
 
 /** Constructor */
 ServerPage::ServerPage(QWidget *parent)
-: ConfigPage(parent, tr("Server"))
+: ConfigPage(parent, "Server")
 {
   /* Invoke the Qt Designer generated object setup routine */
   ui.setupUi(this);
@@ -119,6 +119,13 @@
   delete _settings;
 }
 
+/** Called when the user changes the UI translation. */
+void
+ServerPage::retranslateUi()
+{
+  ui.retranslateUi(this);
+}
+
 /** Called when Vidalia has authenticated to Tor. If the user's Tor is not
  * recent enough, this disables the bridge server option and displays a
  * warning if the user had previously configured Tor as a bridge. */

Modified: vidalia/trunk/src/vidalia/config/serverpage.h
===================================================================
--- vidalia/trunk/src/vidalia/config/serverpage.h	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/config/serverpage.h	2008-10-13 00:11:28 UTC (rev 3220)
@@ -52,6 +52,8 @@
   /** Returns true if the user has changed their server settings since the
    * last time they were applied to Tor. */
   bool changedSinceLastApply();
+  /** Called when the user changes the UI translation. */
+  virtual void retranslateUi();
 
 private slots:
   /** Called when the user toggles any one of the server mode radio buttons

Modified: vidalia/trunk/src/vidalia/config/servicepage.cpp
===================================================================
--- vidalia/trunk/src/vidalia/config/servicepage.cpp	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/config/servicepage.cpp	2008-10-13 00:11:28 UTC (rev 3220)
@@ -24,7 +24,7 @@
 
 /** Constructor */
 ServicePage::ServicePage(QWidget *parent)
-: ConfigPage(parent, tr("Services"))
+: ConfigPage(parent, "Services")
 {
   /* Invoke the Qt Designer generated object setup routine */
   ui.setupUi(this);
@@ -69,6 +69,13 @@
   delete _serviceSettings;
 }
 
+/** Called when the user changes the UI translation. */
+void
+ServicePage::retranslateUi()
+{
+  ui.retranslateUi(this);
+}
+
 /** Saves changes made to settings on the Server settings page. */
 bool
 ServicePage::save(QString &errmsg)

Modified: vidalia/trunk/src/vidalia/config/servicepage.h
===================================================================
--- vidalia/trunk/src/vidalia/config/servicepage.h	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/config/servicepage.h	2008-10-13 00:11:28 UTC (rev 3220)
@@ -34,6 +34,8 @@
   void load();
   /** Initialize the service table */
   void initServiceTable(QMap<int, Service>* _services);
+  /** Called when the user changes the UI translation. */
+  virtual void retranslateUi();
 
 private slots:
   /** Called whenever the user clicks on the 'add' button. */

Modified: vidalia/trunk/src/vidalia/help/browser/helpbrowser.cpp
===================================================================
--- vidalia/trunk/src/vidalia/help/browser/helpbrowser.cpp	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/help/browser/helpbrowser.cpp	2008-10-13 00:11:28 UTC (rev 3220)
@@ -94,6 +94,16 @@
   ui.treeContents->setItemExpanded(ui.treeContents->topLevelItem(0), true);
 }
 
+/** Called when the user changes the UI translation. */
+void
+HelpBrowser::retranslateUi()
+{
+  ui.retranslateUi(this);
+  ui.treeContents->clear();
+  loadContentsFromXml(":/help/" + language() + "/contents.xml");
+  ui.treeContents->setItemExpanded(ui.treeContents->topLevelItem(0), true);
+}
+
 /** Returns the language in which help topics should appear, or English
  * ("en") if no translated help files exist for the current GUI language. */
 QString
@@ -286,7 +296,7 @@
   return 0;
 }
 
-/** Shows the help browser. If a sepcified topic was given, the search for
+/** Shows the help browser. If a sepcified topic was given, then search for
  * that topic's ID (e.g., "log.basic") and display the appropriate page. */
 void
 HelpBrowser::showTopic(QString topic)
@@ -294,13 +304,15 @@
   /* Search for the topic in the contents tree */
   QTreeWidgetItem *item =
     findTopicItem(ui.treeContents->topLevelItem(0), topic);
-  
+  QTreeWidgetItem *selected = 0;
+
   if (item) {
     /* Item was found, so show its location in the hierarchy and select its
      * tree item. */
-    QTreeWidgetItem* selected = ui.treeContents->selectedItems()[0];
-    if (selected) {
-      ui.treeContents->setItemSelected(selected, false);
+    if (ui.treeContents->selectedItems().size()) {
+      selected = ui.treeContents->selectedItems()[0];
+      if (selected)
+        ui.treeContents->setItemSelected(selected, false);
     }
     ui.treeContents->setItemExpanded(ui.treeContents->topLevelItem(0), true);
     ui.treeContents->setItemSelected(item, true);

Modified: vidalia/trunk/src/vidalia/help/browser/helpbrowser.h
===================================================================
--- vidalia/trunk/src/vidalia/help/browser/helpbrowser.h	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/help/browser/helpbrowser.h	2008-10-13 00:11:28 UTC (rev 3220)
@@ -40,7 +40,11 @@
 public slots:
   /** Overrides the default QWidget::show() */
   void showWindow(QString topic = QString());
-  
+
+protected:
+  /** Called when the user changes the UI translation. */
+  virtual void retranslateUi();
+
 private slots:
   /** Called when the user clicks "Find Next" */
   void findNext();

Modified: vidalia/trunk/src/vidalia/languagesupport.cpp
===================================================================
--- vidalia/trunk/src/vidalia/languagesupport.cpp	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/languagesupport.cpp	2008-10-13 00:11:28 UTC (rev 3220)
@@ -14,9 +14,7 @@
 ** \brief Contains languages supported by Vidalia
 */
 
-#include <QTranslator>
 #include <QLocale>
-#include <QLibraryInfo>
 #include <vidalia.h>
 
 #include "languagesupport.h"
@@ -121,44 +119,3 @@
   return languageCodes().contains(languageCode);
 }
 
-/** Sets the application's translator to the specified language. */
-bool
-LanguageSupport::translate(const QString &languageCode)
-{
-  if (!isValidLanguageCode(languageCode))
-    return false;
-  if (languageCode == "en")
-    return true;
-
-  /* Attempt to load the translations for Qt's internal widgets from their
-   * installed Qt directory. */
-  QTranslator *systemQtTranslator = new QTranslator(vApp);
-  Q_CHECK_PTR(systemQtTranslator);
-
-  QString qtDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
-  if (systemQtTranslator->load(qtDir + "/qt_" + languageCode + ".qm"))
-    QApplication::installTranslator(systemQtTranslator);
-  else
-    delete systemQtTranslator;
-
-  /* Install the translator for Qt's internal widgets that is shipped with
-   * Vidalia. */
-  QTranslator *qtTranslator = new QTranslator(vApp);
-  Q_CHECK_PTR(qtTranslator);
-
-  if (qtTranslator->load(":/lang/qt_" + languageCode + ".qm"))
-    QApplication::installTranslator(qtTranslator);
-  else 
-    delete qtTranslator;
-
-  /* Install a translator for Vidalia's UI widgets */
-  QTranslator *vidaliaTranslator = new QTranslator(vApp);
-  Q_CHECK_PTR(vidaliaTranslator);
-
-  if (vidaliaTranslator->load(":/lang/vidalia_" + languageCode + ".qm")) {
-    QApplication::installTranslator(vidaliaTranslator);
-    return true;
-  }
-  delete vidaliaTranslator;
-  return false;
-}

Modified: vidalia/trunk/src/vidalia/languagesupport.h
===================================================================
--- vidalia/trunk/src/vidalia/languagesupport.h	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/languagesupport.h	2008-10-13 00:11:28 UTC (rev 3220)
@@ -17,7 +17,6 @@
 #ifndef _LANGUAGESUPPORT_H
 #define _LANGUAGESUPPORT_H
 
-#include <QApplication>
 #include <QStringList>
 #include <QMap>
 
@@ -39,8 +38,6 @@
   static QMap<QString, QString> languages();
   /** Returns true if we understand the given language code. */
   static bool isValidLanguageCode(const QString &languageCode);
-  /** Sets the application's translator to the specified language. */
-  static bool translate(const QString &languageCode);
 };
 
 #endif

Modified: vidalia/trunk/src/vidalia/log/messagelog.cpp
===================================================================
--- vidalia/trunk/src/vidalia/log/messagelog.cpp	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/log/messagelog.cpp	2008-10-13 00:11:28 UTC (rev 3220)
@@ -136,6 +136,14 @@
                                 "interest to Tor developers.")); 
 }
 
+/** Called when the user changes the UI translation. */
+void
+MessageLog::retranslateUi()
+{
+  ui.retranslateUi(this);
+  setToolTips();
+}
+
 /** Loads the saved Message Log settings */
 void
 MessageLog::loadSettings()

Modified: vidalia/trunk/src/vidalia/log/messagelog.h
===================================================================
--- vidalia/trunk/src/vidalia/log/messagelog.h	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/log/messagelog.h	2008-10-13 00:11:28 UTC (rev 3220)
@@ -42,7 +42,9 @@
 protected:
   /** Called to deliver custom event types */
   void customEvent(QEvent *event);
-  
+  /** Called when the user changes the UI translation. */
+  virtual void retranslateUi();
+
 private slots:
   /** Called when the user triggers the save all action **/
   void saveAll();

Modified: vidalia/trunk/src/vidalia/main.cpp
===================================================================
--- vidalia/trunk/src/vidalia/main.cpp	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/main.cpp	2008-10-13 00:11:28 UTC (rev 3220)
@@ -25,6 +25,7 @@
 #include <QSysInfo>
 #endif
 
+
 /** Returns true if there is already another Vidalia process running. */
 bool
 is_vidalia_running(QString pidfile)

Modified: vidalia/trunk/src/vidalia/mainwindow.cpp
===================================================================
--- vidalia/trunk/src/vidalia/mainwindow.cpp	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/mainwindow.cpp	2008-10-13 00:11:28 UTC (rev 3220)
@@ -104,6 +104,7 @@
   _bandwidthGraph = new BandwidthGraph();
   _netViewer      = new NetViewer();
   _configDialog   = new ConfigDialog();
+  _menuBar        = 0;
   connect(_messageLog, SIGNAL(helpRequested(QString)),
           this, SLOT(showHelpDialog(QString)));
   connect(_netViewer, SIGNAL(helpRequested(QString)),
@@ -197,6 +198,28 @@
   delete _configDialog;
 }
 
+void
+MainWindow::retranslateUi()
+{
+  ui.retranslateUi(this);
+  updateTorStatus(_status);
+
+  _bandwidthAct->setText(tr("Bandwidth Graph"));
+  _messageAct->setText(tr("Message Log"));
+  _networkAct->setText(tr("Network Map"));
+  _controlPanelAct->setText(tr("Control Panel"));
+  _helpAct->setText(tr("Help"));
+  _newIdentityAct->setText(tr("New Identity"));
+
+#if !defined(Q_WS_MAC)
+  _aboutAct->setText(tr("About"));
+  _configAct->setText(tr("Settings"));
+  _exitAct->setText(tr("Exit"));
+#else
+  createMenuBar();
+#endif
+}
+
 /** Catches and processes Tor client and general status events. */
 void
 MainWindow::customEvent(QEvent *event)
@@ -437,30 +460,35 @@
 
   /* Force Qt to put merge the Exit, Configure, and About menubar options into
    * the default menu, even if Vidalia is currently not speaking English. */
-  _exitAct->setText("exit");
   _configAct->setText("config");
+  _configAct->setMenuRole(QAction::PreferencesRole);
   _aboutAct->setText("about");
-  
+  _aboutAct->setMenuRole(QAction::AboutRole);
+  _exitAct->setText("quit");
+  _exitAct->setMenuRole(QAction::QuitRole);
+
   /* The File, Help, and Configure menus will get merged into the application
    * menu by Qt. */
-  QMenuBar *menuBar = new QMenuBar(0);
-  QMenu *fileMenu = menuBar->addMenu(tr("File"));
+  if (_menuBar)
+    delete _menuBar;
+  _menuBar = new QMenuBar(0);
+  QMenu *fileMenu = _menuBar->addMenu("File");
   fileMenu->addAction(_exitAct);
-  
-  QMenu *torMenu = menuBar->addMenu(tr("Tor"));
+  fileMenu->addAction(_configAct);
+
+  QMenu *torMenu = _menuBar->addMenu(tr("Tor"));
   torMenu->addAction(_startStopAct);
   torMenu->addSeparator();
   torMenu->addAction(_newIdentityAct);
 
-  QMenu *viewMenu = menuBar->addMenu(tr("View"));
+  QMenu *viewMenu = _menuBar->addMenu(tr("View"));
   viewMenu->addAction(_controlPanelAct);
   viewMenu->addSeparator();
   viewMenu->addAction(_bandwidthAct);
   viewMenu->addAction(_messageAct);
   viewMenu->addAction(_networkAct);
-  viewMenu->addAction(_configAct);
   
-  QMenu *helpMenu = menuBar->addMenu(tr("Help"));
+  QMenu *helpMenu = _menuBar->addMenu(tr("Help"));
   _helpAct->setText(tr("Vidalia Help"));
   helpMenu->addAction(_helpAct);
   helpMenu->addAction(_aboutAct);
@@ -481,7 +509,6 @@
 
   if (!executable.isEmpty())
     _imProcess->start(executable, QStringList());
-  
 }
 
 /** Called when browser or IM client have exited */

Modified: vidalia/trunk/src/vidalia/mainwindow.h
===================================================================
--- vidalia/trunk/src/vidalia/mainwindow.h	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/mainwindow.h	2008-10-13 00:11:28 UTC (rev 3220)
@@ -52,6 +52,8 @@
 protected:
   /** Catches and processes Tor client status events. */
   virtual void customEvent(QEvent *event);
+  /** Called when the user changes the UI translation. */
+  virtual void retranslateUi();
 
 private slots:
   /** Displays the help browser and displays the most recently viewed help
@@ -212,6 +214,8 @@
   QTimer _updateTimer;
   /** The Glider process used to check for and download updates. */
   GliderProcess _gliderProcess;
+  /** The menubar (Mac OS X only). */
+  QMenuBar *_menuBar;
 
   /** Defines the actions for the tray menu */
   QAction* _controlPanelAct;

Modified: vidalia/trunk/src/vidalia/network/netviewer.cpp
===================================================================
--- vidalia/trunk/src/vidalia/network/netviewer.cpp	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/network/netviewer.cpp	2008-10-13 00:11:28 UTC (rev 3220)
@@ -114,6 +114,13 @@
              this,   SLOT(resolved(int, QList<GeoIp>)));
 }
 
+/** Called when the user changes the UI translation. */
+void
+NetViewer::retranslateUi()
+{
+  ui.retranslateUi(this);
+}
+
 /** Display the network map window. If there are geoip requests waiting in the
  * queue, start the queue timers now. */
 void

Modified: vidalia/trunk/src/vidalia/network/netviewer.h
===================================================================
--- vidalia/trunk/src/vidalia/network/netviewer.h	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/network/netviewer.h	2008-10-13 00:11:28 UTC (rev 3220)
@@ -54,6 +54,8 @@
 protected:
   /** Called to deliver a NEWDESC event from Tor. */
   void customEvent(QEvent *event);
+  /** Called when the user changes the UI translation. */
+  void retranslateUi();
 
 private slots:
   /** Called when the user selects the "Help" action on the toolbar. */

Modified: vidalia/trunk/src/vidalia/vidalia.cpp
===================================================================
--- vidalia/trunk/src/vidalia/vidalia.cpp	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/vidalia.cpp	2008-10-13 00:11:28 UTC (rev 3220)
@@ -19,6 +19,8 @@
 #include <QTextStream>
 #include <QStyleFactory>
 #include <QShortcut>
+#include <QTranslator>
+#include <QLibraryInfo>
 #include <languagesupport.h>
 #include <vmessagebox.h>
 #include <stringutil.h>
@@ -44,6 +46,7 @@
 QString Vidalia::_language;            /**< The current language.            */
 TorControl* Vidalia::_torControl = 0;  /**< Main TorControl object.          */
 Log Vidalia::_log;
+QList<QTranslator *> Vidalia::_translators;
 
 /** Catches debugging messages from Qt and sends them to Vidalia's logs. If Qt
  * emits a QtFatalMsg, we will write the message to the log and then abort().
@@ -271,7 +274,7 @@
     languageCode = settings.getLanguageCode();
   }
   /* Translate into the desired langauge */
-  if (LanguageSupport::translate(languageCode)) {
+  if (retranslateUi(languageCode)) {
     _language = languageCode;
     return true;
   }
@@ -354,3 +357,64 @@
 {
   createShortcut(QKeySequence(key), sender, receiver, slot);
 }
+
+void
+Vidalia::removeAllTranslators()
+{
+  foreach (QTranslator *translator, _translators) {
+    QApplication::removeTranslator(translator);
+    delete translator;
+  }
+  _translators.clear();
+}
+
+bool
+Vidalia::retranslateUi(const QString &languageCode)
+{
+  QTranslator *systemQtTranslator = 0;
+  QTranslator *vidaliaQtTranslator = 0;
+  QTranslator *vidaliaTranslator = 0;
+
+  if (! LanguageSupport::isValidLanguageCode(languageCode))
+    return false;
+  if (! languageCode.compare("en", Qt::CaseInsensitive)) {
+    removeAllTranslators();
+    return true;
+  }
+
+  systemQtTranslator = new QTranslator(vApp);
+  Q_CHECK_PTR(systemQtTranslator);
+  QString qtDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
+  systemQtTranslator->load(qtDir + "/qt_" + languageCode + ".qm");
+
+
+  vidaliaQtTranslator = new QTranslator(vApp);
+  Q_CHECK_PTR(vidaliaQtTranslator);
+  vidaliaQtTranslator->load(":/lang/qt_" + languageCode + ".qm");
+
+  vidaliaTranslator = new QTranslator(vApp);
+  Q_CHECK_PTR(vidaliaTranslator);
+  if (! vidaliaTranslator->load(":/lang/vidalia_" + languageCode + ".qm"))
+    goto err;
+
+  removeAllTranslators();
+  _language = languageCode;
+  QApplication::installTranslator(systemQtTranslator);
+  QApplication::installTranslator(vidaliaQtTranslator);
+  QApplication::installTranslator(vidaliaTranslator);
+  _translators << systemQtTranslator
+               << vidaliaQtTranslator
+               << vidaliaTranslator;
+  return true;
+
+err:
+  if (systemQtTranslator)
+    delete systemQtTranslator;
+  if (vidaliaQtTranslator)
+    delete vidaliaQtTranslator;
+  if (vidaliaTranslator)
+    delete vidaliaTranslator;
+  delete vidaliaTranslator;
+  return false;
+}
+

Modified: vidalia/trunk/src/vidalia/vidalia.h
===================================================================
--- vidalia/trunk/src/vidalia/vidalia.h	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/vidalia.h	2008-10-13 00:11:28 UTC (rev 3220)
@@ -24,6 +24,7 @@
 
 #include <QApplication>
 #include <QMap>
+#include <QList>
 #include <QString>
 #include <QKeySequence>
 
@@ -102,6 +103,14 @@
   static void createShortcut(const QString &key, QWidget *sender,
                              QObject *receiver, const char *slot);
 
+  /** Loads and installs all available translators for the specified
+   * <b>languageCode</b>. All currently installed QTranslator objects will be
+   * removed. Returns true if at least Vidalia's language file can be loaded
+   * for the given language. Otherwise, returns false and no change is made
+   * to the current translators.
+   */
+  static bool retranslateUi(const QString &languageCode);
+
 signals:
   /** Emitted when the application is running and the main event loop has
    * started. */ 
@@ -115,6 +124,9 @@
   bool winEventFilter(MSG *msg, long *result);
 #endif
 
+  /** Removes all currently installed QTranslators. */
+  static void removeAllTranslators();
+
 private slots:
   /** Called when the application's main event loop has started. This method
    * will emit the running() signal to indicate that the application's event
@@ -136,6 +148,7 @@
   static QString _language;            /**< The current language.            */
   static TorControl* _torControl;      /**< Vidalia's main TorControl object.*/
   static Log _log; /**< Logs debugging messages to file or stdout. */
+  static QList<QTranslator *> _translators; /**< List of installed translators. */
 };
 
 #endif

Modified: vidalia/trunk/src/vidalia/vidaliawindow.cpp
===================================================================
--- vidalia/trunk/src/vidalia/vidaliawindow.cpp	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/vidaliawindow.cpp	2008-10-13 00:11:28 UTC (rev 3220)
@@ -126,3 +126,25 @@
   QMainWindow::setVisible(visible);
 }
 
+/** Reimplement the windows' changeEvent() method to check if the event
+ * is a QEvent::LanguageChange event. If so, call retranslateUi(), which
+ * subclasses of VidaliaWindow can reimplement to update their UI. */
+void
+VidaliaWindow::changeEvent(QEvent *e)
+{
+  if (e->type() == QEvent::LanguageChange) {
+    retranslateUi();
+    e->accept();
+    return;
+  }
+  QMainWindow::changeEvent(e);
+}
+
+/** Called when the user wants to change the currently visible language.
+ * Subclasses can reimplement this to update their UI. */
+void
+VidaliaWindow::retranslateUi()
+{
+  /* The default retranslateUi() implementation does nothing */
+}
+

Modified: vidalia/trunk/src/vidalia/vidaliawindow.h
===================================================================
--- vidalia/trunk/src/vidalia/vidaliawindow.h	2008-10-08 01:46:51 UTC (rev 3219)
+++ vidalia/trunk/src/vidalia/vidaliawindow.h	2008-10-13 00:11:28 UTC (rev 3220)
@@ -48,6 +48,14 @@
   /** Saves a value associated with a setting name for this window object. */
   void saveSetting(QString name, QVariant value);
 
+protected:
+  /** Reimplement the windows' changeEvent() method to check if the event
+   * is a QEvent::LanguageChange event. If so, call retranslateUi(), which
+   * subclasses of VidaliaWindow can reimplement to update their UI. */
+  virtual void changeEvent(QEvent *e);
+  /** Called when the user wants to change the currently visible language. */
+  virtual void retranslateUi();
+
 public slots:
   /** Shows or hides this window. */
   virtual void setVisible(bool visible);