commit 919ccb92304fe86bda1d11ad6758871ccd483185 Author: Kathy Brade brade@pearlcrescent.com Date: Thu Oct 15 15:59:59 2015 -0400
Bug 12967: Prompt for language during first run.
The intl.locale.matchOS pref is set to true by default so that the lanuage prompt is presented in the OS/system language. To skip the language prompt, set the TOR_SKIP_LOCALE_PROMPT env variable to 1 or set the hidden pref extensions.torlauncher.prompt_for_locale to false. --- src/chrome/content/localePicker.xul | 62 +++++++++++ src/chrome/content/network-settings.js | 158 ++++++++++++++++++++++------- src/chrome/locale/en/network-settings.dtd | 4 + src/chrome/skin/network-settings.css | 5 + src/components/tl-process.js | 59 ++++++++--- src/defaults/preferences/prefs.js | 4 + src/modules/tl-util.jsm | 20 ++++ 7 files changed, 260 insertions(+), 52 deletions(-)
diff --git a/src/chrome/content/localePicker.xul b/src/chrome/content/localePicker.xul new file mode 100644 index 0000000..be82e14 --- /dev/null +++ b/src/chrome/content/localePicker.xul @@ -0,0 +1,62 @@ +<?xml version="1.0"?> +<!-- + - Copyright (c) 2015, The Tor Project, Inc. + - See LICENSE for licensing information. + - vim: set sw=2 sts=2 ts=8 et syntax=xml: + --> + +<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> +<?xml-stylesheet href="chrome://torlauncher/skin/network-settings.css" + type="text/css"?> + +<!DOCTYPE overlay SYSTEM "chrome://torlauncher/locale/network-settings.dtd"> + +<?xul-overlay href="chrome://torlauncher/content/network-settings-overlay.xul"?> + +<wizard id="TorLauncherLocalePicker" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + title="&torlauncher.localePicker.title;" + windowtype="TorLauncher:LocalePicker" + persist="screenX screenY" + onwizardfinish="return setLocale();" + onwizardcancel="return onCancel();" + onload="initLocaleDialog();"> + + <script type="application/x-javascript" + src="chrome://torlauncher/content/network-settings.js"/> + + <wizardpage pageid="localePicker"> + <hbox class="tbb-header"> + <vbox class="tbb-logo-box" align="start"> + <image class="tbb-logo" /> + </vbox> + </hbox> + <separator /> + <vbox> + <label class="question">&torlauncher.localePicker.prompt;</label> + <separator/> + <listbox id="localeList" ondblclick="onLocaleListDoubleClick()"> + <listitem value="en-US" label="English" selected="true" /> + <listitem value="ar" label="العربية" /> + <listitem value="de" label="Deutsch" /> + <listitem value="es-ES" label="Español" /> + <listitem value="fa" label="فارسی" /> + <listitem value="fr" label="Français" /> + <listitem value="it" label="Italiano" /> + <listitem value="ja" label="日本語" /> + <listitem value="ko" label="한국어" /> + <listitem value="nl" label="Nederlands" /> + <listitem value="pl" label="Polski" /> + <listitem value="pt-PT" label="Português (Europeu)" /> + <listitem value="ru" label="Русский" /> + <listitem value="tr" label="Türkçe" /> + <listitem value="vi" label="Tiếng Việt" /> + <listitem value="zh-CN" label="简体字" /> + </listbox> + </vbox> + </wizardpage> + + <hbox pack="start"> + <label id="forAssistance" /> + </hbox> +</wizard> diff --git a/src/chrome/content/network-settings.js b/src/chrome/content/network-settings.js index e4ebeaa..2382ea6 100644 --- a/src/chrome/content/network-settings.js +++ b/src/chrome/content/network-settings.js @@ -15,6 +15,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "TorLauncherUtil", XPCOMUtils.defineLazyModuleGetter(this, "TorLauncherLogger", "resource://torlauncher/modules/tl-logger.jsm");
+const kPrefPromptForLocale = "extensions.torlauncher.prompt_for_locale"; +const kPrefLocale = "general.useragent.locale"; +const kPrefMatchOSLocale = "intl.locale.matchOS"; + const kPrefDefaultBridgeRecommendedType = "extensions.torlauncher.default_bridge_recommended_type"; const kPrefDefaultBridgeType = "extensions.torlauncher.default_bridge_type"; @@ -31,6 +35,7 @@ const kTorLogHasWarnOrErrTopic = "TorLogHasWarnOrErr"; const kWizardProxyRadioGroup = "proxyRadioGroup"; const kWizardUseBridgesRadioGroup = "useBridgesRadioGroup";
+const kLocaleList = "localeList"; const kUseProxyCheckbox = "useProxy"; const kProxyTypeMenulist = "proxyType"; const kProxyAddr = "proxyAddr"; @@ -58,29 +63,78 @@ const kTorConfKeyBridgeList = "Bridge"; var gProtocolSvc = null; var gTorProcessService = null; var gObsService = null; +var gHasQuitButton = false; var gIsInitialBootstrap = false; var gIsBootstrapComplete = false; var gRestoreAfterHelpPanelID = null; var gActiveTopics = []; // Topics for which an observer is currently installed.
-function initDialog() +function initDialogCommon(aHasQuitButton) { - var isWindows = TorLauncherUtil.isWindows; + gHasQuitButton = aHasQuitButton; + + gObsService = Cc["@mozilla.org/observer-service;1"] + .getService(Ci.nsIObserverService); + + let isWindows = TorLauncherUtil.isWindows; if (isWindows) document.documentElement.setAttribute("class", "os-windows"); else if (TorLauncherUtil.isMac) document.documentElement.setAttribute("class", "os-mac");
- var forAssistance = document.getElementById("forAssistance"); + let forAssistance = document.getElementById("forAssistance"); if (forAssistance) { forAssistance.textContent = TorLauncherUtil.getFormattedLocalizedString( "forAssistance", [kSupportAddr], 1); }
- var cancelBtn = document.documentElement.getButton("cancel"); + if (aHasQuitButton) + { + let cancelBtn = document.documentElement.getButton("cancel"); + if (cancelBtn) + { + let quitKey = isWindows ? "quit_win" : "quit"; + cancelBtn.label = TorLauncherUtil.getLocalizedString(quitKey); + } + } + + let wizardElem = getWizard(); + let haveWizard = (wizardElem != null); + if (haveWizard) + { + // Hide the Tor Browser logo and associated separator element if the + // TOR_HIDE_BROWSER_LOGO environment variable is set. + let env = Cc["@mozilla.org/process/environment;1"] + .getService(Ci.nsIEnvironment); + if (env.exists("TOR_HIDE_BROWSER_LOGO")) + wizardElem.setAttribute("tor_hide_browser_logo", true); + } +} + + +function resizeDialogToFitContent() +{ + // Resize this window to fit content. sizeToContent() alone will not do + // the job (it has many limitations and it is buggy). + sizeToContent(); + let w = maxWidthOfContent(); + if (w) + { + let windowFrameWidth = window.outerWidth - window.innerWidth; + w += windowFrameWidth; + + if (w > window.outerWidth) + window.resizeTo(w, window.outerHeight); + } +} + + +function initDialog() +{ gIsInitialBootstrap = window.arguments[0]; + initDialogCommon(gIsInitialBootstrap);
var startAtPanel; if (window.arguments.length > 1) @@ -88,12 +142,6 @@ function initDialog()
if (gIsInitialBootstrap) { - if (cancelBtn) - { - var quitKey = isWindows ? "quit_win" : "quit"; - cancelBtn.label = TorLauncherUtil.getLocalizedString(quitKey); - } - var okBtn = document.documentElement.getButton("accept"); if (okBtn) okBtn.label = TorLauncherUtil.getLocalizedString("connect"); @@ -115,25 +163,16 @@ function initDialog() } catch (e) { dump(e + "\n"); }
- gObsService = Cc["@mozilla.org/observer-service;1"] - .getService(Ci.nsIObserverService); - var wizardElem = getWizard(); var haveWizard = (wizardElem != null); if (haveWizard) { - // Hide the Tor Browser logo and associated separator element if the - // TOR_HIDE_BROWSER_LOGO environment variable is set. - let env = Cc["@mozilla.org/process/environment;1"] - .getService(Ci.nsIEnvironment); - if (env.exists("TOR_HIDE_BROWSER_LOGO")) - wizardElem.setAttribute("tor_hide_browser_logo", true); - // Set "Copy Tor Log" label and move it after the Quit (cancel) button. var copyLogBtn = document.documentElement.getButton("extra2"); if (copyLogBtn) { copyLogBtn.label = wizardElem.getAttribute("buttonlabelextra2"); + var cancelBtn = document.documentElement.getButton("cancel"); if (cancelBtn && TorLauncherUtil.isMac) cancelBtn.parentNode.insertBefore(copyLogBtn, cancelBtn.nextSibling); } @@ -191,20 +230,44 @@ function initDialog() showPanel(); }
- // Resize this window to fit content. sizeToContent() alone will not do - // the job (it has many limitations and it is buggy). - sizeToContent(); - let w = maxWidthOfContent(); - if (w) + resizeDialogToFitContent(); + + TorLauncherLogger.log(2, "initDialog done"); +} + + +function initLocaleDialog() +{ + initDialogCommon(true); + + // Replace the finish button's label ("Done") with the next button's + // label ("Next" or "Continue"). + let nextBtn = document.documentElement.getButton("next"); + let doneBtn = document.documentElement.getButton("finish"); + if (nextBtn && doneBtn) + doneBtn.label = nextBtn.label; + + // Select the current language by default. + try { - let windowFrameWidth = window.outerWidth - window.innerWidth; - w += windowFrameWidth; + let chromeRegSvc = Cc["@mozilla.org/chrome/chrome-registry;1"] + .getService(Ci.nsIXULChromeRegistry); + let curLocale = chromeRegSvc.getSelectedLocale("global").toLowerCase(); + let localeList = document.getElementById(kLocaleList); + for (let i = 0; i < localeList.itemCount; ++i) + { + let item = localeList.getItemAtIndex(i); + if (item.value.toLowerCase() == curLocale) + { + localeList.selectedIndex = i; + break; + } + } + } catch (e) {}
- if (w > window.outerWidth) - window.resizeTo(w, window.outerHeight); - } + resizeDialogToFitContent();
- TorLauncherLogger.log(2, "initDialog done"); + TorLauncherLogger.log(2, "initLocaleDialog done"); }
@@ -243,7 +306,9 @@ function maxWidthOfContent()
function getWizard() { - var elem = document.getElementById("TorNetworkSettings"); + let elem = document.getElementById("TorNetworkSettings"); + if (!elem) + elem = document.getElementById("TorLauncherLocalePicker"); return (elem && (elem.tagName == "wizard")) ? elem : null; }
@@ -677,6 +742,27 @@ function restoreButtonLabel(aID) }
+function onLocaleListDoubleClick() +{ + getWizard().advance(); +} + + +function setLocale() +{ + let locale = getElemValue(kLocaleList, "en-US"); + if (TorLauncherUtil.isMac && ("ja" == locale)) + locale = "ja-JP-mac"; + TorLauncherUtil.setCharPref(kPrefLocale, locale); + TorLauncherUtil.setBoolPref(kPrefPromptForLocale, false); + TorLauncherUtil.setBoolPref(kPrefMatchOSLocale, false); + + // Clear cached strings so the new locale takes effect. + TorLauncherUtil.flushLocalizedStringCache(); + gObsService.notifyObservers(null, "chrome-flush-caches", null); +} + + function onProxyTypeChange() { var proxyType = getElemValue(kProxyTypeMenulist, null); @@ -707,11 +793,9 @@ function onCancel() return false; }
- if (gIsInitialBootstrap) try + if (gHasQuitButton) try { - var obsSvc = Cc["@mozilla.org/observer-service;1"] - .getService(Ci.nsIObserverService); - obsSvc.notifyObservers(null, "TorUserRequestedQuit", null); + gObsService.notifyObservers(null, "TorUserRequestedQuit", null); } catch (e) {}
return true; @@ -1389,6 +1473,7 @@ function setElemValue(aID, aValue) } // fallthru case "menulist": + case "listbox": elem.value = (val) ? val : ""; break; } @@ -1435,6 +1520,7 @@ function getElemValue(aID, aDefaultValue) break; case "textbox": case "menulist": + case "listbox": rv = elem.value; break; } diff --git a/src/chrome/locale/en/network-settings.dtd b/src/chrome/locale/en/network-settings.dtd index 07d3d09..b193750 100644 --- a/src/chrome/locale/en/network-settings.dtd +++ b/src/chrome/locale/en/network-settings.dtd @@ -1,5 +1,9 @@ <!ENTITY torsettings.dialog.title "Tor Network Settings">
+<!-- For locale picker: --> +<!ENTITY torlauncher.localePicker.title "Tor Browser Language"> +<!ENTITY torlauncher.localePicker.prompt "Please select a language."> + <!-- For "first run" wizard: -->
<!ENTITY torsettings.prompt "Before you connect to the Tor network, you need to provide information about this computer's Internet connection."> diff --git a/src/chrome/skin/network-settings.css b/src/chrome/skin/network-settings.css index 6e173c3..610ab26 100644 --- a/src/chrome/skin/network-settings.css +++ b/src/chrome/skin/network-settings.css @@ -99,6 +99,11 @@ wizard[tor_hide_browser_logo="true"] .tbb-logo-separator { display: none; }
+wizard#TorLauncherLocalePicker button[dlgtype="back"], +wizard#TorLauncherLocalePicker button[dlgtype="next"] { + display: none; +} + .tbb-wizardpage-title { font-size: 115%; font-weight: bold; diff --git a/src/components/tl-process.js b/src/components/tl-process.js index 216c962..5113203 100644 --- a/src/components/tl-process.js +++ b/src/components/tl-process.js @@ -425,6 +425,17 @@ TorProcessService.prototype =
_controlTor: function() { + // Optionally prompt for locale. Blocks until dialog is closed. + if (TorLauncherUtil.shouldPromptForLocale) + { + this._openLocalePicker(); + if (this.mQuitSoon) + { + this._quitApp(); + return; + } + } + try { this._monitorTorProcessStartup(); @@ -446,7 +457,7 @@ TorProcessService.prototype = if (this.mObsSvc) this.mObsSvc.notifyObservers(null, "TorOpenProgressDialog", null); } - else + else if (!this.TorIsBootstrapDone) { this._openProgressDialog();
@@ -457,21 +468,8 @@ TorProcessService.prototype = }
// If the user pressed "Quit" within settings/progress, exit. - if (this.mQuitSoon) try - { - this.mQuitSoon = false; - - var asSvc = Cc["@mozilla.org/toolkit/app-startup;1"] - .getService(Ci.nsIAppStartup); - var flags = asSvc.eAttemptQuit; - if (this.mRestartWithQuit) - flags |= asSvc.eRestart; - asSvc.quit(flags); - } - catch (e) - { - TorLauncherLogger.safelog(4, "unable to quit browser", e); - } + if (this.mQuitSoon) + this._quitApp(); } catch (e) { @@ -482,6 +480,25 @@ TorProcessService.prototype = } }, // controlTor()
+ _quitApp: function() + { + try + { + this.mQuitSoon = false; + + var asSvc = Cc["@mozilla.org/toolkit/app-startup;1"] + .getService(Ci.nsIAppStartup); + var flags = asSvc.eAttemptQuit; + if (this.mRestartWithQuit) + flags |= asSvc.eRestart; + asSvc.quit(flags); + } + catch (e) + { + TorLauncherLogger.safelog(4, "unable to quit", e); + } + }, + _monitorTorProcessStartup: function() { this.mControlConnDelayMS = this.kInitialControlConnDelayMS; @@ -579,6 +596,16 @@ TorProcessService.prototype = TorLauncherUtil.showSaveSettingsAlert(null, errObj.details); },
+ _openLocalePicker: function() + { + const kLocalePickerURL = "chrome://torlauncher/content/localePicker.xul"; + + var wwSvc = Cc["@mozilla.org/embedcomp/window-watcher;1"] + .getService(Ci.nsIWindowWatcher); + var winFeatures = "chrome,dialog=yes,modal,all"; + wwSvc.openWindow(null, kLocalePickerURL, "_blank", winFeatures, undefined); + }, + // If this window is already open, put up "starting tor" panel, focus it and return. // Otherwise, open the network settings dialog and block until it is closed. _openNetworkSettings: function(aIsInitialBootstrap, aStartAtWizardPanel) diff --git a/src/defaults/preferences/prefs.js b/src/defaults/preferences/prefs.js index 34bf1a7..3057f6a 100644 --- a/src/defaults/preferences/prefs.js +++ b/src/defaults/preferences/prefs.js @@ -1,3 +1,7 @@ +// When presenting the setup wizard, first prompt for locale. +pref("intl.locale.matchOS", true); +pref("extensions.torlauncher.prompt_for_locale", true); + pref("extensions.torlauncher.loglevel", 4); // 1=verbose, 2=debug, 3=info, 4=note, 5=warn pref("extensions.torlauncher.logmethod", 1); // 0=stdout, 1=errorconsole, 2=debuglog pref("extensions.torlauncher.max_tor_log_entries", 1000); diff --git a/src/modules/tl-util.jsm b/src/modules/tl-util.jsm index ac680a8..812b32b 100644 --- a/src/modules/tl-util.jsm +++ b/src/modules/tl-util.jsm @@ -112,6 +112,10 @@ let TorLauncherUtil = // Public },
// Localized Strings + flushLocalizedStringCache: function() + { + TLUtilInternal.mStringBundle = undefined; + },
// "torlauncher." is prepended to aStringName. getLocalizedString: function(aStringName) @@ -258,6 +262,22 @@ let TorLauncherUtil = // Public return this.getBoolPref(kPrefStartTor, true); },
+ get shouldPromptForLocale() + { + const kPrefPromptForLocale = "extensions.torlauncher.prompt_for_locale"; + try + { + const kEnvSkipLocalePrompt = "TOR_SKIP_LOCALE_PROMPT"; + + var env = Cc["@mozilla.org/process/environment;1"] + .getService(Ci.nsIEnvironment); + if (env.exists(kEnvSkipLocalePrompt)) + return ("1" != env.get(kEnvSkipLocalePrompt)); + } catch(e) {} + + return this.getBoolPref(kPrefPromptForLocale, true); + }, + get shouldShowNetworkSettings() { const kPrefPromptAtStartup = "extensions.torlauncher.prompt_at_startup";