Repository: nvaccess/nvda

Issue:
NVDA menu and settings options either missing hotkeys or hotkey not visually underlined.
This issue initially only covered "Report formatting changes after the cursor".  For completeness, I have recorded below all NVDA menu and settings options which either do not have a hotkey or for which the hotkey is not underlined.

When you press NVDA+n and bring up the NVDA menu, the hotkey (the letter you can press to activate that item) is underlined on most options.  For instance, the "C" in "Configuration profiles" is underlined, indicating you can press C to directly open the configuration profiles screen.

In the NVDA menu and sub-menus, there are several options where the hotkey is not underlined in the menu item and should be.

In the main NVDA menu, "Tools" should have "T" underlined, and "Donate" should have "D" underlined.

In the Tools menu, ONLY "Manage add-ons" has a letter underlined ("a"), so the rest need their hotkey letter underlined.

In the Help menu, the "About" option should have the "A" underlined.

In the "Settings" dialog (looking at the new combined multi-settings dialog), the following options do not have hotkeys underlined:
- General Page: "Use NVDA on the Windows logon screen"
- Speech Page: "Automatic language switching",
	"Automatic dialect switching"
	"Trust Voice's language..." and
	"Capital pitch change percentage"
- Braille page: "Blind cursor"
	"Cursor blink rate" and 
	"Focus context presentation"
- Keyboard page: "Use Capslock as an NVDA modifier"
	"Use numpad Insert as an NVDA modifier"
	"Use extended Insert as an NVDA modifier"
	"Speech interrupt for typed characters"
	"Speech interrupt for Enter key" and
	"Beep if typing lowercase letters when caps lock is turned on"
- Review cursor: "Simple review mode"
- Object presentation: "Report background progress bars"
- Browse mode: "Automatic focus mode for focus changes"
	"Automatic focus mode for caret movement" and
	'Audio indication of focus and browse modes"
- Document formatting: "Cell borders" and
	"Report formatting changes after the cursor"
	
And for completeness:
- In the Add-ons manager, there is no hotkey displayed for the "Installed add-ons" list itself.
- In the Create portable copy dialog, the Browse button does not have a hotkey.
Wording of options
Feedback on GUI, received via email. With respect to the general settings dialog, though the concept should apply to all dialogs.

> Wording can be improved for some options to make the purpose clearer and to shorten the text and apply some consistency.  Some suggestions follow:
> 
> Language (requires restart to fully take effect):  combo box  User default  collapsed 
> Do we mean restart of nvda or restart of windows? so wording could be changed to: 
> Language (changes take effect after restarting NVDA):  combo box  User default  collapsed
> 
> Save configuration on exit  check box  checked 
> could be re-worded to 
> Save configuration on exiting NVDA  check box  checked
> 
> Show exit options when exiting NVDA  check box  not checked 
> could be re-worded to 
> Confirm before exiting NVDA  check box  not checked
> 
> Automatically start NVDA after I log on to Windows  check box  not checked 
> could be re-worded to 
> Automatically start NVDA after logging on to Windows  check box  not checked
> 
> Use currently saved settings on the logon and other secure screens (requires administrator privileges)  button 
> could be shorter and re-worded to: 
> Use saved settings on logon and secure screens (requires administrator privileges)  button



Discussion:
I also notice that the Cell borders combo box does not have a hotkey either. Suggestions on what they should be?
Even though I believe the "report formatting changes after the cursor" option usage is discouraged, for consistency it, and the "cell borders" combo box should have an accelerator. I don't think either of these missing accelerators are particularly important, I'll label this as a P3 Bug and good for new dev. 

### Next steps:
List out the accelerators that are already used in this dialog, and suggest accelerator keys for these two options.

### Code:
Is in `source/gui/settingsDialogs.py` in `class DocumentFormattingDialog`
Add an ampersand (`&`) in front of the letter chosen to be an accelerator.
@feerrenrut: I'd say a p4 is sufficient for this? Setting this as good for new dev

Resolving patch:
diff --git a/source/gui/settingsDialogs.py b/source/gui/settingsDialogs.py
--- a/source/gui/settingsDialogs.py
+++ b/source/gui/settingsDialogs.py
@@ -1,9 +1,8 @@
 # -*- coding: UTF-8 -*-
-# settingsDialogs.py
 # A part of NonVisual Desktop Access (NVDA)
 # Copyright (C) 2006-2020 NV Access Limited, Peter Vágner, Aleksey Sadovoy,
 # Rui Batista, Joseph Lee, Heiko Folkerts, Zahari Yurukov, Leonard de Ruijter,
-#  Derek Riemer, Babbage B.V., Davy Kager, Ethan Holliger, Bill Dengler
+# Derek Riemer, Babbage B.V., Davy Kager, Ethan Holliger, Bill Dengler, Thomas Stivers
 # This file is covered by the GNU General Public License.
 # See the file COPYING for more details.
 
@@ -662,8 +661,10 @@ def makeSettings(self, settingsSizer):
 		settingsSizerHelper = guiHelper.BoxSizerHelper(self, sizer=settingsSizer)
 		self.languageNames = languageHandler.getAvailableLanguages(presentational=True)
 		languageChoices = [x[1] for x in self.languageNames]
-		# Translators: The label for a setting in general settings to select NVDA's interface language (once selected, NVDA must be restarted; the option user default means the user's Windows language will be used).
-		languageLabelText = _("&Language (requires restart to fully take effect):")
+		# Translators: The label for a setting in general settings to select NVDA's interface language
+		# (once selected, NVDA must be restarted; the option user default means the user's Windows language
+		# will be used).
+		languageLabelText = _("NVDA &Language (requires restart):")
 		self.languageList=settingsSizerHelper.addLabeledControl(languageLabelText, wx.Choice, choices=languageChoices)
 		self.languageList.SetToolTip(wx.ToolTip("Choose the language NVDA's messages and user interface should be presented in."))
 		try:
@@ -675,8 +676,9 @@ def makeSettings(self, settingsSizer):
 		if globalVars.appArgs.secure:
 			self.languageList.Disable()
 
-		# Translators: The label for a setting in general settings to save current configuration when NVDA exits (if it is not checked, user needs to save configuration before quitting NVDA).
-		self.saveOnExitCheckBox=wx.CheckBox(self,label=_("&Save configuration on exit"))
+		# Translators: The label for a setting in general settings to save current configuration when NVDA
+		# exits (if it is not checked, user needs to save configuration before quitting NVDA).
+		self.saveOnExitCheckBox = wx.CheckBox(self, label=_("&Save configuration when exiting NVDA"))
 		self.saveOnExitCheckBox.SetValue(config.conf["general"]["saveConfigurationOnExit"])
 		if globalVars.appArgs.secure:
 			self.saveOnExitCheckBox.Disable()
@@ -692,7 +694,9 @@ def makeSettings(self, settingsSizer):
 		self.playStartAndExitSoundsCheckBox.SetValue(config.conf["general"]["playStartAndExitSounds"])
 		settingsSizerHelper.addItem(self.playStartAndExitSoundsCheckBox)
 
-		# Translators: The label for a setting in general settings to select logging level of NVDA as it runs (available options and what they are logged are found under comments for the logging level messages themselves).
+		# Translators: The label for a setting in general settings to select logging level of NVDA as it runs
+		# (available options and what they are logging are found under comments for the logging level messages
+		# themselves).
 		logLevelLabelText=_("L&ogging level:")
 		logLevelChoices = [name for level, name in self.LOG_LEVELS]
 		self.logLevelList = settingsSizerHelper.addLabeledControl(logLevelLabelText, wx.Choice, choices=logLevelChoices)
@@ -706,8 +710,10 @@ def makeSettings(self, settingsSizer):
 		else:
 			log.debugWarning("Could not set log level list to current log level")
 
-		# Translators: The label for a setting in general settings to allow NVDA to start after logging onto Windows (if checked, NvDA will start automatically after loggin into Windows; if not, user must start NVDA by pressing the shortcut key (CTRL+Alt+N by default).
-		self.startAfterLogonCheckBox = wx.CheckBox(self, label=_("&Automatically start NVDA after I log on to Windows"))
+		# Translators: The label for a setting in general settings to allow NVDA to start after logging onto
+		# Windows (if checked, NVDA will start automatically after logging into Windows; if not, user must
+		# start NVDA by pressing the shortcut key (CTRL+Alt+N by default).
+		self.startAfterLogonCheckBox = wx.CheckBox(self, label=_("St&art NVDA after Windows sign in"))
 		self.startAfterLogonCheckBox.SetValue(config.getStartAfterLogon())
 		if globalVars.appArgs.secure or not config.isInstalledCopy():
 			self.startAfterLogonCheckBox.Disable()
@@ -947,7 +953,7 @@ def makeSettings(self, settingsSizer):
 		# device combo in the synthesizer dialog. Examples of
 		# of an output device are default soundcard, usb
 		# headphones, etc.
-		deviceListLabelText = _("Output &device:")
+		deviceListLabelText = _("Audio output  &device:")
 		deviceNames=nvwave.getOutputDeviceNames()
 		self.deviceList = settingsSizerHelper.addLabeledControl(deviceListLabelText, wx.Choice, choices=deviceNames)
 
@@ -958,7 +964,7 @@ def makeSettings(self, settingsSizer):
 		self.deviceList.SetSelection(selection)
 
 		# Translators: This is a label for the audio ducking combo box in the Synthesizer Settings dialog.
-		duckingListLabelText=_("Audio &ducking mode:")
+		duckingListLabelText = _("Audio d&ucking mode:")
 		self.duckingList=settingsSizerHelper.addLabeledControl(duckingListLabelText, wx.Choice, choices=audioDucking.audioDuckingModes)
 		index=config.conf['audio']['audioDuckingMode']
 		self.duckingList.SetSelection(index)
@@ -1011,7 +1017,7 @@ def onOk(self, evt):
 		super(SynthesizerSelectionDialog, self).onOk(evt)
 
 class DriverSettingChanger(object):
-	"""Functor which acts as calback for GUI events."""
+	"""Functor which acts as callback for GUI events."""
 
 	def __init__(self,driver,setting):
 		self._driverRef=weakref.ref(driver)
@@ -1515,13 +1521,13 @@ def makeSettings(self, settingsSizer):
 
 		# Translators: This is the label for a checkbox in the
 		# keyboard settings panel.
-		speechInterruptForCharText = _("Speech interrupt for typed characters")
+		speechInterruptForCharText = _("Speech &interrupt for typed characters")
 		self.speechInterruptForCharsCheckBox=sHelper.addItem(wx.CheckBox(self,label=speechInterruptForCharText))
 		self.speechInterruptForCharsCheckBox.SetValue(config.conf["keyboard"]["speechInterruptForCharacters"])
 
 		# Translators: This is the label for a checkbox in the
 		# keyboard settings panel.
-		speechInterruptForEnterText = _("Speech interrupt for Enter key")
+		speechInterruptForEnterText = _("Speech i&nterrupt for Enter key")
 		self.speechInterruptForEnterCheckBox=sHelper.addItem(wx.CheckBox(self,label=speechInterruptForEnterText))
 		self.speechInterruptForEnterCheckBox.SetValue(config.conf["keyboard"]["speechInterruptForEnter"])
 
@@ -1533,13 +1539,13 @@ def makeSettings(self, settingsSizer):
 
 		# Translators: This is the label for a checkbox in the
 		# keyboard settings panel.
-		beepForLowercaseWithCapsLockText = _("Beep if typing lowercase letters when caps lock is on")
+		beepForLowercaseWithCapsLockText = _("&Beep if typing lowercase letters when caps lock is on")
 		self.beepLowercaseCheckBox=sHelper.addItem(wx.CheckBox(self,label=beepForLowercaseWithCapsLockText))
 		self.beepLowercaseCheckBox.SetValue(config.conf["keyboard"]["beepForLowercaseWithCapslock"])
 
 		# Translators: This is the label for a checkbox in the
 		# keyboard settings panel.
-		commandKeysText = _("Speak command &keys")
+		commandKeysText = _("Speak c&ommand keys")
 		self.commandKeysCheckBox=sHelper.addItem(wx.CheckBox(self,label=commandKeysText))
 		self.commandKeysCheckBox.SetValue(config.conf["keyboard"]["speakCommandKeys"])
 
@@ -1558,7 +1564,7 @@ def makeSettings(self, settingsSizer):
 		self.handleInjectedKeysCheckBox.SetValue(config.conf["keyboard"]["handleInjectedKeys"])
 
 	def isValid(self):
-		# #2871: check wether at least one key is the nvda key.
+		# #2871: check whether at least one key is the nvda key.
 		if not self.modifierList.CheckedItems:
 			log.debugWarning("No NVDA key set")
 			gui.messageBox(
@@ -1657,22 +1663,22 @@ class ReviewCursorPanel(SettingsPanel):
 	def makeSettings(self, settingsSizer):
 		# Translators: This is the label for a checkbox in the
 		# review cursor settings panel.
-		self.followFocusCheckBox=wx.CheckBox(self,wx.ID_ANY,label=_("Follow system &focus"))
+		self.followFocusCheckBox = wx.CheckBox(self, label=_("Follow system &focus"))
 		self.followFocusCheckBox.SetValue(config.conf["reviewCursor"]["followFocus"])
 		settingsSizer.Add(self.followFocusCheckBox,border=10,flag=wx.BOTTOM)
 		# Translators: This is the label for a checkbox in the
 		# review cursor settings panel.
-		self.followCaretCheckBox=wx.CheckBox(self,wx.ID_ANY,label=_("Follow System &Caret"))
+		self.followCaretCheckBox = wx.CheckBox(self, label=_("Follow System &Caret"))
 		self.followCaretCheckBox.SetValue(config.conf["reviewCursor"]["followCaret"])
 		settingsSizer.Add(self.followCaretCheckBox,border=10,flag=wx.BOTTOM)
 		# Translators: This is the label for a checkbox in the
 		# review cursor settings panel.
-		self.followMouseCheckBox=wx.CheckBox(self,wx.ID_ANY,label=_("Follow &mouse cursor"))
+		self.followMouseCheckBox = wx.CheckBox(self, label=_("Follow &mouse cursor"))
 		self.followMouseCheckBox.SetValue(config.conf["reviewCursor"]["followMouse"])
 		settingsSizer.Add(self.followMouseCheckBox,border=10,flag=wx.BOTTOM)
 		# Translators: This is the label for a checkbox in the
 		# review cursor settings panel.
-		self.simpleReviewModeCheckBox=wx.CheckBox(self,wx.ID_ANY,label=_("Simple review mode"))
+		self.simpleReviewModeCheckBox = wx.CheckBox(self, label=_("&Simple review mode"))
 		self.simpleReviewModeCheckBox.SetValue(config.conf["reviewCursor"]["simpleReviewMode"])
 		settingsSizer.Add(self.simpleReviewModeCheckBox,border=10,flag=wx.BOTTOM)
 
@@ -1770,7 +1776,7 @@ def makeSettings(self, settingsSizer):
 
 		# Translators: This is the label for a checkbox in the
 		# object presentation settings panel.
-		guessPositionInfoText=_("Guess object &position information when unavailable")
+		guessPositionInfoText = _("&Guess object &position information when unavailable")
 		self.guessPositionInfoCheckBox=sHelper.addItem(wx.CheckBox(self,label=guessPositionInfoText))
 		self.guessPositionInfoCheckBox.SetValue(config.conf["presentation"]["guessObjectPositionInformationWhenUnavailable"])
 
@@ -1794,7 +1800,7 @@ def makeSettings(self, settingsSizer):
 
 		# Translators: This is the label for a checkbox in the
 		# object presentation settings panel.
-		reportBackgroundProgressBarsText = _("Report background progress bars")
+		reportBackgroundProgressBarsText = _("Report backg&round progress bars")
 		self.reportBackgroundProgressBarsCheckBox=sHelper.addItem(wx.CheckBox(self,label=reportBackgroundProgressBarsText))
 		self.reportBackgroundProgressBarsCheckBox.SetValue(config.conf["presentation"]["progressBarUpdates"]["reportBackgroundProgressBars"])
 
@@ -1804,7 +1810,7 @@ def makeSettings(self, settingsSizer):
 		self.dynamicContentCheckBox=sHelper.addItem(wx.CheckBox(self,label=dynamicContentText))
 		self.dynamicContentCheckBox.SetValue(config.conf["presentation"]["reportDynamicContentChanges"])
 
-		# Translators: This is the label for a combobox in the
+		# Translators: This is the label for a checkbox in the
 		# object presentation settings panel.
 		autoSuggestionsLabelText = _("Play a sound when &auto-suggestions appear")
 		self.autoSuggestionSoundsCheckBox=sHelper.addItem(wx.CheckBox(self,label=autoSuggestionsLabelText))
@@ -1937,7 +1943,7 @@ def makeSettings(self, settingsSizer):
 
 		# Translators: This is the label for a checkbox in the
 		# document formatting settings panel.
-		fontAttributesText = _("Font attri&butes")
+		fontAttributesText = _("Font attrib&utes")
 		self.fontAttrsCheckBox=fontGroup.addItem(wx.CheckBox(self,label=fontAttributesText))
 		self.fontAttrsCheckBox.SetValue(config.conf["documentFormatting"]["reportFontAttributes"])
 
@@ -2079,9 +2085,13 @@ def makeSettings(self, settingsSizer):
 			# document formatting settings panel.
 			_("Both Colors and Styles"),
 		]
-		# Translators: This is the label for a combobox in the
-		# document formatting settings panel.
-		self.borderComboBox=tablesGroup.addLabeledControl(_("Cell borders:"), wx.Choice, choices=borderChoices)
+		self.borderComboBox = tablesGroup.addLabeledControl(
+			# Translators: This is the label for a combobox in the
+			# document formatting settings panel.
+			_("Cell &borders:"),
+			wx.Choice,
+			choices=borderChoices
+		)
 		curChoice = 0
 		if config.conf["documentFormatting"]["reportBorderStyle"]:
 			if config.conf["documentFormatting"]["reportBorderColor"]:
@@ -2145,7 +2155,7 @@ def makeSettings(self, settingsSizer):
 
 		# Translators: This is the label for a checkbox in the
 		# document formatting settings panel.
-		detectFormatAfterCursorText =_("Report formatting changes after the cursor (can cause a lag)")
+		detectFormatAfterCursorText = _("Report formatting chan&ges after the cursor (can cause a lag)")
 		self.detectFormatAfterCursorCheckBox=wx.CheckBox(self, label=detectFormatAfterCursorText)
 		self.detectFormatAfterCursorCheckBox.SetValue(config.conf["documentFormatting"]["detectFormatAfterCursor"])
 		sHelper.addItem(self.detectFormatAfterCursorCheckBox)
@@ -2609,7 +2619,7 @@ def __init__(self,parent,title,speechDict):
 
 	def makeSettings(self, settingsSizer):
 		sHelper = guiHelper.BoxSizerHelper(self, sizer=settingsSizer)
-		# Translators: The label for the combo box of dictionary entries in speech dictionary dialog.
+		# Translators: The label for the list box of dictionary entries in speech dictionary dialog.
 		entriesLabelText=_("&Dictionary entries")
 		self.dictList = sHelper.addLabeledControl(
 			entriesLabelText,
@@ -3583,7 +3593,7 @@ def __init__(self, parent):
 		sHelper = guiHelper.BoxSizerHelper(self, orientation=wx.VERTICAL)
 
 		# Translators: This is the label for the edit field in the add symbol dialog.
-		symbolText = _("Symbol:")
+		symbolText = _("&Symbol:")
 		self.identifierTextCtrl = sHelper.addLabeledControl(symbolText, wx.TextCtrl)
 
 		sHelper.addDialogDismissButtons(self.CreateButtonSizer(wx.OK | wx.CANCEL))
@@ -3638,6 +3648,7 @@ def makeSettings(self, settingsSizer):
 
 		# Translators: The label for a column in symbols list used to identify a symbol.
 		self.symbolsList.InsertColumn(0, _("Symbol"), width=self.scaleSize(150))
+		# Translators: The label for a column in symbols list used to identify a replacement.
 		self.symbolsList.InsertColumn(1, _("Replacement"))
 		# Translators: The label for a column in symbols list used to identify a symbol's speech level (either none, some, most, all or character).
 		self.symbolsList.InsertColumn(2, _("Level"))


Test patch: