11# A part of NonVisual Desktop Access (NVDA)
2- # Copyright (C) 2007-2021 NV access Limited, Joseph Lee
2+ # Copyright (C) 2007-2021 NV access Limited, Joseph Lee, Łukasz Golonka
33# This file is covered by the GNU General Public License.
44# See the file COPYING for more details.
55
1818import globalVars
1919from logHandler import log
2020import winKernel
21- from typing import Optional
21+ from typing import List , Optional , Tuple
2222
2323#a few Windows locale constants
2424LOCALE_USER_DEFAULT = 0x400
@@ -118,8 +118,12 @@ def windowsLCIDToLocaleName(lcid: int) -> Optional[str]:
118118 if lang :
119119 return normalizeLanguage (lang )
120120
121- def getLanguageDescription (language ):
121+
122+ def getLanguageDescription (language : str ) -> Optional [str ]:
122123 """Finds out the description (localized full name) of a given local name"""
124+ if language == "Windows" :
125+ # Translators: the label for the Windows default NVDA interface language.
126+ return _ ("User default" )
123127 desc = None
124128 LCID = localeNameToWindowsLCID (language )
125129 if LCID is not LCID_NONE :
@@ -218,21 +222,27 @@ def ansiCodePageFromNVDALocale(localeName: str) -> Optional[str]:
218222 return None
219223
220224
221- def getAvailableLanguages (presentational = False ):
222- """generates a list of locale names, plus their full localized language and country names.
223- @param presentational: whether this is meant to be shown alphabetically by language description
224- @type presentational: bool
225- @rtype: list of tuples
226- """
227- #Make a list of all the locales found in NVDA's locale dir
225+ def listNVDALocales () -> List [str ]:
226+ # Make a list of all the locales found in NVDA's locale dir
228227 localesDir = os .path .join (globalVars .appDir , 'locale' )
229228 locales = [
230229 x for x in os .listdir (localesDir ) if os .path .isfile (os .path .join (localesDir , x , 'LC_MESSAGES' , 'nvda.mo' ))
231230 ]
232- #Make sure that en (english) is in the list as it may not have any locale files, but is default
231+ # Make sure that en (english) is in the list as it may not have any locale files, but is default
233232 if 'en' not in locales :
234233 locales .append ('en' )
235234 locales .sort ()
235+ # include a 'user default, windows' language,
236+ # which just represents the default language for this user account
237+ locales .insert (0 , "Windows" )
238+ return locales
239+
240+
241+ def getAvailableLanguages (presentational : bool = False ) -> List [Tuple [str , str ]]:
242+ """generates a list of locale names, plus their full localized language and country names.
243+ @param presentational: whether this is meant to be shown alphabetically by language description
244+ """
245+ locales = listNVDALocales ()
236246 # Prepare a 2-tuple list of language code and human readable language description.
237247 langs = [(lc , getLanguageDescription (lc )) for lc in locales ]
238248 # Translators: The pattern defining how languages are displayed and sorted in in the general
@@ -243,13 +253,14 @@ def getAvailableLanguages(presentational=False):
243253 isDescFirst = fullDescPattern .find ("{desc}" ) < fullDescPattern .find ("{lc}" )
244254 if presentational and isDescFirst :
245255 langs .sort (key = lambda lang : locale .strxfrm (lang [1 ] if lang [1 ] else lang [0 ]))
246- langs = [(lc , (fullDescPattern .format (desc = desc , lc = lc ) if desc else lc )) for lc , desc in langs ]
247- #include a 'user default, windows' language, which just represents the default language for this user account
248- langs .insert (
249- 0 ,
250- # Translators: the label for the Windows default NVDA interface language.
251- ("Windows" , _ ("User default" ))
252- )
256+ # Make sure that the 'user default' language is first in the list.
257+ for index , lang in enumerate (langs ):
258+ if lang [0 ] == "Windows" :
259+ break
260+ userDefault = langs .pop (index )
261+ langs = [userDefault ] + [
262+ (lc , (fullDescPattern .format (desc = desc , lc = lc ) if desc else lc )) for lc , desc in langs
263+ ]
253264 return langs
254265
255266
@@ -274,6 +285,27 @@ def pgettext(context, message):
274285 raise ValueError ("%s is Not a GNUTranslations or NullTranslations object" % translations )
275286 return pgettext
276287
288+
289+ def getLanguageCliArgs () -> Tuple [str , ...]:
290+ """Returns all command line arguments which were used to set current NVDA language
291+ or an empty tuple if language has not been specified from the CLI."""
292+ for argIndex , argValue in enumerate (sys .argv ):
293+ if argValue == "--lang" :
294+ # Language was provided in a form `--lang lang_CODE`. The next position in `sys.argv` is a language code.
295+ # It is impossible not to provide it in this case as it would be flagged as an error
296+ # during arguments validation.
297+ return (argValue , sys .argv [argIndex + 1 ])
298+ if argValue .startswith ("--lang=" ):
299+ # Language in a form `--lang=lang_CODE`
300+ return (argValue ,)
301+ return tuple ()
302+
303+
304+ def isLanguageForced () -> bool :
305+ """Returns `True` if language is provided from the command line - `False` otherwise."""
306+ return bool (getLanguageCliArgs ())
307+
308+
277309def getWindowsLanguage ():
278310 """
279311 Fetches the locale name of the user's configured language in Windows.
@@ -423,7 +455,7 @@ def getLanguage() -> str:
423455 return curLang
424456
425457
426- def normalizeLanguage (lang ) -> Optional [str ]:
458+ def normalizeLanguage (lang : str ) -> Optional [str ]:
427459 """
428460 Normalizes a language-dialect string in to a standard form we can deal with.
429461 Converts any dash to underline, and makes sure that language is lowercase and dialect is upercase.
0 commit comments