@@ -90,7 +90,7 @@ def path_to_braille_folder():
9090 return os .path .expanduser ("~" ) + "\\ AppData\\ Roaming\\ nvda\\ addons\\ mathCAT\\ globalPlugins\\ MathCAT\\ Rules\\ Braille"
9191
9292 @staticmethod
93- def LanguagesDict ():
93+ def LanguagesDict () -> Dict [ str , str ] :
9494 languages = {
9595 "aa" : "Afar" ,
9696 "ab" : "Аҧсуа" ,
@@ -268,8 +268,30 @@ def LanguagesDict():
268268 return languages
269269
270270 def GetLanguages (self ):
271+
272+ def addRegionalLanguages (subDir : str , language : str ) -> bool :
273+ # the language variants are in folders named using ISO 3166-1 alpha-2
274+ # codes https://en.wikipedia.org/wiki/ISO_3166-2
275+ # check if there are language variants in the language folder
276+ if subDir != "SharedRules" :
277+ languagesDict = UserInterface .LanguagesDict ()
278+ # add to the listbox the text for this language variant together with the code
279+ if languagesDict .get (language + "-" + subDir .upper (), "missing" ) != "missing" :
280+ self .m_choiceLanguage .Append (
281+ languagesDict [language + "-" + subDir .upper ()] + " (" + language + "-" + subDir + ")"
282+ )
283+ elif languagesDict .get (language , "missing" ) != "missing" :
284+ self .m_choiceLanguage .Append (
285+ languagesDict [language ] + " (" + language + "-" + subDir + ")"
286+ )
287+ else :
288+ self .m_choiceLanguage .Append (
289+ language + " (" + language + "-" + subDir + ")"
290+ )
291+ return subDir != "SharedRules"
292+
271293 # initialise the language list
272- languages_dict = UserInterface .LanguagesDict ()
294+ languagesDict = UserInterface .LanguagesDict ()
273295 # clear the language names in the dialog
274296 self .m_choiceLanguage .Clear ()
275297 # Translators: menu item -- use the language of the voice chosen in the NVDA speech settings dialog
@@ -279,40 +301,31 @@ def GetLanguages(self):
279301 # the implemented languages are in folders named using the relevant ISO 639-1
280302 # code https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
281303 for language in os .listdir (UserInterface .path_to_languages_folder ()):
282- if os .path .isdir ( os . path . join (UserInterface .path_to_languages_folder (), language )):
283- path_to_language_folder = os .path .join ( UserInterface . path_to_languages_folder (), language )
304+ pathToLanguageDir = os .path .join (UserInterface .path_to_languages_folder (), language )
305+ if os .path .isdir ( pathToLanguageDir ):
284306 # only add this language if there is a xxx_Rules.yaml file
285- files = glob .glob (os .path .join (path_to_language_folder , "*_Rules.yaml" ))
286- if len (files ) == 0 :
287- # look in the .zip file for the style files -- it might not have been unzipped
288- zip_file = ZipFile (f"{ path_to_language_folder } \\ { language } .zip" , "r" )
289- files = [name for name in zip_file .namelist () if name .endswith ('_Rules.yaml' )]
290- if files :
307+ ruleFilesWereFound = len (glob .glob (os .path .join (pathToLanguageDir , "*_Rules.yaml" ))) > 0
308+ for dir in os .listdir (pathToLanguageDir ):
309+ if os .path .isdir (os .path .join (pathToLanguageDir , dir )):
310+ ruleFilesWereFound |= addRegionalLanguages (dir , language )
311+
312+ if not ruleFilesWereFound :
313+ # look in the .zip file for the style files, including regional subdirs -- it might not have been unzipped
314+ try :
315+ zip_file = ZipFile (f"{ pathToLanguageDir } \\ { language } .zip" , "r" )
316+ for file in zip_file .namelist ():
317+ if file .endswith ('_Rules.yaml' ):
318+ ruleFilesWereFound = True
319+ elif zip_file .getinfo (file ).is_dir ():
320+ ruleFilesWereFound |= addRegionalLanguages (dir , language )
321+ except Exception as e :
322+ log .debugWarning (f"MathCAT Dialog: didn't find zip file { zip_file } . Error: { e } " )
323+ if ruleFilesWereFound :
291324 # add to the listbox the text for this language together with the code
292- if languages_dict .get (language , "missing" ) != "missing" :
293- self .m_choiceLanguage .Append (languages_dict [language ] + " (" + language + ")" )
325+ if languagesDict .get (language , "missing" ) != "missing" :
326+ self .m_choiceLanguage .Append (languagesDict [language ] + " (" + language + ")" )
294327 else :
295328 self .m_choiceLanguage .Append (language + " (" + language + ")" )
296- # the language variants are in folders named using ISO 3166-1 alpha-2
297- # codes https://en.wikipedia.org/wiki/ISO_3166-2
298- # check if there are language variants in the language folder
299- for variant in os .listdir (path_to_language_folder ):
300- if os .path .isdir (os .path .join (path_to_language_folder , variant )):
301- if variant != "SharedRules" :
302- # add to the listbox the text for this language variant together with the code
303- if languages_dict .get (language + "-" + variant .upper (), "missing" ) != "missing" :
304- self .m_choiceLanguage .Append (
305- languages_dict [language + "-" + variant .upper ()] + " (" + language + "-" + variant + ")"
306- )
307- else :
308- if languages_dict .get (language , "missing" ) != "missing" :
309- self .m_choiceLanguage .Append (
310- languages_dict [language ] + " (" + language + "-" + variant + ")"
311- )
312- else :
313- self .m_choiceLanguage .Append (
314- language + " (" + language + "-" + variant + ")"
315- )
316329
317330 def GetLanguageCode (self ):
318331 lang_selection = self .m_choiceLanguage .GetStringSelection ()
@@ -322,37 +335,60 @@ def GetLanguageCode(self):
322335 return lang_code
323336
324337 def GetSpeechStyles (self , this_SpeechStyle : str ):
338+ """Get all the speech styles for the current language.
339+ This sets the SpeechStyles dialog entry"""
325340 from speech import getCurrentLanguage
326341
342+ def getSpeechStyleFromDirectory (dir : str , lang : str ) -> list [str ]:
343+ r"""Get the speech styles from any regional dialog, from the main language, dir and if there isn't from the zip file.
344+ The 'lang', if it has a region dialect, is of the form 'en\uk'
345+ The returned list is sorted alphabetically"""
346+ # start with the regional dialect, then add on any (unique) styles in the main dir
347+ main_lang = lang .split ("\\ " )[0 ] # does the right thing even if there is no regional directory
348+ all_style_files = []
349+ if lang .find ("\\ " ) >= 0 :
350+ all_style_files = [os .path .basename (name ) for name in glob .glob (dir + lang + "\\ *_Rules.yaml" )]
351+ all_style_files .extend (
352+ [os .path .basename (name ) for name in glob .glob (dir + main_lang + "\\ *_Rules.yaml" )]
353+ )
354+ all_style_files = list (set (all_style_files )) # make them unique
355+ if len (all_style_files ) == 0 :
356+ # look in the .zip file for the style files -- this will have regional variants, but also have that dir
357+ try :
358+ zip_file = dir + main_lang + "\\ " + main_lang + ".zip"
359+ zip_file = ZipFile (zip_file , "r" ) # file might not exist
360+ all_style_files = [name .split ("/" )[- 1 ] for name in zip_file .namelist () if name .endswith ('_Rules.yaml' )]
361+ except Exception as e :
362+ log .debugWarning (f"MathCAT Dialog: didn't find zip file { zip_file } . Error: { e } " )
363+ all_style_files .sort ()
364+ return all_style_files
365+
327366 # clear the SpeechStyle choices
328367 self .m_choiceSpeechStyle .Clear ()
329368 # get the currently selected language code
330- this_language_code = UserInterface .GetLanguageCode (self )
369+ languageCode = UserInterface .GetLanguageCode (self )
331370
332- if this_language_code == "Auto" :
371+ if languageCode == "Auto" :
333372 # list the speech styles for the current voice rather than have none listed
334- this_language_code = getCurrentLanguage ().lower ().replace ("_" , "-" )
335- # FIX: when dialog is aware of regional dialects, remove this next line that removes the dialect part
336- this_language_code = this_language_code .split ("-" )[0 ] # grab the first part
373+ languageCode = getCurrentLanguage ().lower ().replace ("_" , "-" )
374+ languageCode = languageCode .replace ("-" , "\\ " )
337375
338- this_language_path = (
376+ languagePath = (
339377 os .path .expanduser ("~" )
340378 + "\\ AppData\\ Roaming\\ nvda\\ addons\\ MathCAT\\ globalPlugins\\ MathCAT\\ Rules\\ Languages\\ "
341- + this_language_code
342379 )
343- this_path = this_language_path + "\\ *_Rules.yaml"
344380 # populate the m_choiceSpeechStyle choices
345- # start with listing unzipped dirs
346- all_style_files = [os .path .basename (name ) for name in glob .glob (this_path )]
347- if len (all_style_files ) == 0 :
348- # look in the .zip file for the style files
349- zip_file = ZipFile (f"{ this_language_path } \\ { this_language_code } .zip" , "r" )
350- all_style_files = [name for name in zip_file .namelist () if name .endswith ('_Rules.yaml' )]
381+ all_style_files = [
382+ # remove "_Rules.yaml" from the list
383+ name [: name .find ("_Rules.yaml" )] for name in getSpeechStyleFromDirectory (languagePath , languageCode )
384+ ]
351385 for name in all_style_files :
352- self .m_choiceSpeechStyle .Append ((name [: name . find ( "_Rules.yaml" )] ))
386+ self .m_choiceSpeechStyle .Append ((name ))
353387 try :
354388 # set the SpeechStyle to the same as previous
355- self .m_choiceSpeechStyle .SetStringSelection (this_SpeechStyle )
389+ self .m_choiceSpeechStyle .SetStringSelection (
390+ this_SpeechStyle if this_SpeechStyle in all_style_files else all_style_files [0 ]
391+ )
356392 except Exception as e :
357393 log .error (f"MathCAT: An exception occurred in GetSpeechStyles evaluating set SetStringSelection: { e } " )
358394 # that didn't work, choose the first in the list
0 commit comments