Repository: nvaccess/nvda

Issue:
In general settings panel, language combo-box is not sorted correctly
<!--
Please thoroughly read NVDA's wiki article on how to fill in this template, including how to provide the required files.
Issues may be closed if the required information is not present.
https://github.com/nvaccess/nvda/wiki/Github-issue-template-explanation-and-examples
-->

### Steps to reproduce:

* Open General  property settings page, e.g. pressing NVDA+Ctrl+G
* Open language combo-box and look at the order of the language list

### Actual behavior:

The list is sorted as follow :
* Afrikaans (Afrique du Sud), af_ZA
* [most of all languages]
* Vietnamien, vi
* macédonien, mk
* norvégien, bokmål (Norvège), nb_NO
* norvégien, nynorsk (Norvège), nn_NO
* User default

### Expected behavior:

The list is sorted as follow :
* Afrikaans (Afrique du Sud), af_ZA
* [all languages]
* Vietnamien, vi
* User default

### Analysis

* The names of the languages are provided by Windows itself ; that's why it is in French here, whatever the language of NVDA.
* Seems that Windows provides 3 language names starting with lower case and the others with upper case.
* A solution would be to sort language names without taking into account case.
* In English or other Windows UI languages, is the issue also present?

### System configuration
#### NVDA installed/portable/running from source:
Installed or portable or source

#### NVDA version:
2019.2.1 and 2019.3

#### Windows version:

Windows 10 1903 and Windows 10 1709, both French UI.

#### Name and version of other software in use when reproducing the issue:

N/A
#### Other information about your system:

### Other questions
#### Does the issue still occur after restarting your PC?

Yes

#### Have you tried any other versions of NVDA? If so, please report their behaviors.

Already present on some earlier versions of NVDA.



Discussion:
CyrilleB79 wrote:

>  *  In English or other Windows UI languages, is the issue also present?

Not in English.

Also not in portuguese.
In Dutch, it's also fine here.

Resolving patch:
diff --git a/source/languageHandler.py b/source/languageHandler.py
--- a/source/languageHandler.py
+++ b/source/languageHandler.py
@@ -101,21 +101,23 @@ def getAvailableLanguages(presentational=False):
 	if 'en' not in locales:
 		locales.append('en')
 		locales.sort()
-	#For each locale, ask Windows for its human readable display name
-	displayNames = []
-	for entry in locales:
-		desc=getLanguageDescription(entry)
-		displayNames.append("%s, %s"%(desc,entry) if desc else entry)
-	#Prepare a zipped view of language codes and descriptions.
-	# #7284: especially for sorting by description.
-	# Python 3: zip function changed from returning a list to an iterator, thus wrap this inside a list call.
-	langs = list(zip(locales,displayNames))
-	if presentational:
-		langs.sort(key=lambda lang: lang[1])
+	# Prepare a 2-tuple list of language code and human readable language description.
+	langs = [(lc, getLanguageDescription(lc)) for lc in locales]
+	# Translators: The pattern defining how languages are displayed and sorted in in the general
+	# setting panel language list. Use "{desc}, {lc}" (most languages) to display first full language
+
+	# name and then ISO; use "{lc}, {desc}" to display first ISO language code and then full language name.
+	fullDescPattern = _("{desc}, {lc}")
+	isDescFirst = fullDescPattern.find("{desc}") < fullDescPattern.find("{lc}")
+	if presentational and isDescFirst:
+		langs.sort(key=lambda lang: locale.strxfrm(lang[1] if lang[1] else lang[0]))
+	langs = [(lc, (fullDescPattern.format(desc=desc, lc=lc) if desc else lc)) for lc, desc in langs]
 	#include a 'user default, windows' language, which just represents the default language for this user account
-	langs.append(("Windows",
+	langs.insert(
+		0,
 		# Translators: the label for the Windows default NVDA interface language.
-		_("User default")))
+		("Windows", _("User default"))
+	)
 	return langs
 
 def makePgettext(translations):
@@ -335,4 +337,3 @@ def normalizeLanguage(lang):
 	136:'wo',
 	140:'gbz'
 }
-


Test patch: