Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add profile specific speech dictionaries #11005

Closed

Conversation

marlon-sousa
Copy link
Contributor

@marlon-sousa marlon-sousa commented Apr 14, 2020

Link to issue number: #3656

Summary of the issue:

NVDA dictionaries are powerful, offering great features such as regular expression processing. However, there is currently no way of applying dictionary processing conditionally.
The way NVDA applies other conditional settings, such as document formatting and others, is through the use of profiles.
Profiles are groups of settings that can, together, be applied conditionally to the screen reader.
However, right until this pull request, dictionary processing wasn't taking in consideration the active profile.

Description of how this pull request fixes the issue:

This pull request implements profile context when processing and creating / editing dictionaries. For a description in terms of behavior, see #3656 (comment)

Bellow is a summary of implementation changes:

Config.ConfigManager

  • Created an accessor method called getMostRecentProfile, offering a better way than conf.profiles[-1] to access active most recent profile information

gui.MainFrame

  • changed onDefaultDictionaryCommand and onVoiceDictionaryCommand methods to reference default and voice dictionaries from a method on speechDictHandler instead of directly, cinse now there can be specific profile dictionaries

gui.SettingsDialogs.DictionaryDialog

  • Created some internal helper methods
  • Added button for importing default dictionary entries, if we are editing specific profile dictionaries
  • created hasPatternEntry method that decides if a given entry is already listed on screen.
  • Added code on onOk method to make sure a new created profile specific dictionary is activated as soon as it is created
  • added onImportEntriesClick to handle activation of import entries from default dictionary button

speechDictHandler module

  • registred for being notified on profile change
  • Created handler for reacting to profile chananges notification
  • created function to reload dictionaries. This will analyse current state (e.e are we under a specific or default profile) and load dictionaries into the system appropriately
  • Created functions getDictionary and _getVoiceDictionary that return on call the correct dictionary object, considering profiles.
  • Created loadProfileDict that will load the correct dictionary on NVDA, considering profiles.
  • Changed the loadVoiceDict function to consider profiles when loading voice dictionary
  • Created other helper functions

speechDictHandler.SpeechDict class

  • added accessor getPattern
  • added create method, which creates and returns an empty dictionary object with its backing file configured
  • added syncFrom method, which takes another SpeechDict object and import its entries to itself, as long as they don't overwrite current ones

dictFormatUpgrade module

  • added function getProfileVoiceDictsPath which correctly resolve voice specific dictionary path

Dictionary files

This PR Creates specific dictionary for profiles on %appdata%\nvda\speechDicts, where the dictionaries are currently saved. Default dictionary (for default profile) is placed on the root folder, as usual. The voice dictionaries for the default profile reside on voiceDicts.v1 subdirectory.

The profile specific dictionaries are placed in subdirectories with the profile name, inside the speechDicts directory.
The default.dict dictionary for each profile is placed on the profile root directory, while voice dictionaries are placed inside the voiceDicts.v1 for each profile.

Migrations are made for default dictionaries only, following the procedure as before. New dictionaries are placed on profile subfolders, as stated avobe.

Why dictionaries are saved on speechDicts folder instead of on profiles folder

This decision was taken because, although a "profiles" folder already exists, profiles aren't created within subfolders. Instead, they are single files scattered at the same folder.

Ideally, each profile should deserve its own subdirectory where the configuration itself plus additional files could live, but taking this step now would envolve a migration tool and discussion with the community, which would be too much for this functionality.

So, by now, dictionary files will reside on speechDicts subfolder and be separated by profiles, and if and when the profiles folder get under discussion we can write a migration tool.

Testing performed:

  1. on default profile, access settings / dictionaries / default.
  2. The title bar shows standard dictionary - normal configuration.
  3. buttons exibited are add, remove, edit, ok and cancel.
  4. Add an entry, for example changing word to word1 and click ok to close the dictionary.
  5. Open notepad.
  6. Type word and perform a read line. You should hear word1.
  7. Activate any profile.
  8. Perform a readline. You should hear word1.
  9. Still with that profile activated, access settings / dictionaries / default.
  10. The title bar shows standard dictionary - [ your profile name]
  11. buttons exibited are add, remove, edit, import entries from the default dictionary, ok and cancel.
  12. The dictionary is empty, as it is new. Hit cancel and back to the notepad.
  13. Make a perform line, you should hear word1.
  14. access settings / dictionaries / default.
  15. The title bar shows default dictionary - [ your profile name].
  16. buttons exibited are add, remove, edit, import entries from the default dictionary, ok and cancel.
  17. Add an entry, for example changing word to word2 and click ok to close the dictionary.
  18. Back to notepad and make a read line. You should hear word2.
  19. Change profile to normal configuration and make a readline on notepad. You should hear word1.
  20. Change to the profile you are using for testing.
  21. access settings / dictionaries / default.
  22. The title bar shows standard dictionary - [ your profile name].
  23. buttons exibited are add, remove, edit, import entries from the default dictionary, ok and cancel.
  24. Remove the word entry and click ok.
  25. on notepad, make a read line. You will hear word, because now the specific dictionary has been created and its empty.
  26. Change profile to normal configuration and make a readline on notepad. You should hear word1.
  27. Change to the profile you are using for testing.
  28. access settings / dictionaries / default.
  29. The title bar shows standard dictionary - [ your profile name].
  30. buttons exibited are add, remove, edit, import entries from the default dictionary, ok and cancel.
  31. The list of entires is empty.
  32. Activate the import entries from the default dictionary button.
  33. You are focused in the entries list and can see all entries from your default dictionary added, including the one you created for word, replacing it by word1. Hit cancel.
  34. Back to notepad, make a readline. You should hear word because the dictionary is still empty.
  35. access settings / dictionaries / default.
  36. The title bar shows standard dictionary - [ your profile name].
  37. buttons exibited are add, remove, edit, import entries from the default dictionary, ok and cancel.
  38. The list of entires is empty.
  39. Activate the import entries from the default dictionary button.
  40. You are focused in the entries list and can see all entries from your default dictionary added, including the one you created for word, replacing it by word1. Hit ok.
  41. Back to notepad, perform a readline. You should hear word1, because you have imported entries from the default dictionary into the profile dictionary.
  42. access settings / dictionaries / default.
  43. The title bar shows standard dictionary - [ your profile name].
  44. buttons exibited are add, remove, edit, import entries from the default dictionary, ok and cancel.
  45. Remove all entries from the dictionary.
  46. Add a new entry replacing word by word3.
  47. Activate the import entries from the default dictionary button.
  48. You are focused in the entries list and can see all entries from your default dictionary added. However, the entry for the word term is replacing by word3, not by word1, because on import the entry from default dictionary didn't overwrite the entry already on this dictionary.
  49. Hit ok. Back to notepad, a read line should speech word3.

All tests above can be performed with voice specific dictionaries. The behaviour will be the same.

Known issues with pull request:

None at this time

Change log entry:

Section: New features, Changes, Bug fixes

@AppVeyorBot
Copy link

@AppVeyorBot
Copy link

See test results for failed build of commit f32a4f25e0

@AppVeyorBot
Copy link

See test results for failed build of commit 9e7debf40a

Copy link

@Carlos-EstebanM Carlos-EstebanM left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello.
In the spanish comunity, the speech dictionarys are used for translation audiogames from english to spanish when the game speak using NVDA. I hope that this change request can be implemented. Is good have a dictionary for translation of a game only in this application, for example.
Regards.

@marlon-sousa
Copy link
Contributor Author

Hello,

While NVDA does not merge this changes you will be happy to know that the very same code that is to be merged fot that is available on an addon, see https://github.com/marlon-sousa/EnhancedDictionaries

@Carlos-EstebanM
Copy link

Carlos-EstebanM commented Jun 9, 2020 via email

@feerrenrut feerrenrut self-requested a review July 1, 2020 13:46
@feerrenrut feerrenrut self-assigned this Jul 1, 2020
Copy link
Contributor

@feerrenrut feerrenrut left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'd like to introduce this change, however there are a few things to address.

  • The latest master will need to be merged in.
  • Please add to the PR description an overview of the different dictionary files involved and how they relate to each other and profiles.
  • Please also summarize how these new files interact with the dictionary upgrade process.

Thanks for your work here @marlon-sousa, I suspect this will be a popular feature for power users.

@@ -642,6 +644,11 @@ def deleteProfile(self, name):
if trigger._profile == delProfile:
del self._suspendedTriggers[trigger]

def getActiveProfile(self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this name confuses concepts used. ConfigManager can have many active profiles, they are consulted in order of most recently activated. This function seems to want to get the most recently activated profile, or the most context specific profile. Please update the name, and add some docs to explain this. It would also be nice to extend the docs for self.profiles to specify that the most recently activated are added to the end of the list.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@feerrenrut as far as I understand how profiles work on NVDA, there is always the base config (a k a default profile) and zero or one other profile in effect at the same time.

The final configuration is then a merge of all default configurations plus the specified configurations on the profile, which will have precedence over these same configurations on the default profile.

Your comment seems to imply that there is a stack of profiles activated, so every configuration is searched, in precedence order, from the upper to the lower profiles, being the default profile the lowest one.

I frankly have never been able to reproduce this kind of behavior, nor has the graphical user interface ever given me this impression, because, from the GUI, it seems clear that only one profile can be activated at any time, not multiple profiles (either you have the default profile activated or some other being either something you manually activated or that the loader decided that should be activated).

So far, up to now, every time I activated a profile their configurations came in effect immediately, and configuration the previous profile specified were discarded.

For example:

  1. Configure your default profile to use eSpeak American English voice.
  2. Create another profile, say test1, and configure it to use British English Voice.
  3. Create another profile, say test2, and do not change the voice settings.

Now, do the following:

  1. Activate the default probile and read a word. You should hear the American English Voice.
  2. Now, activate the test1 profile manually and read the same word. You should hear it using the British English Voice.
  3. Now, Activate the test2 profile, that one you didn't supply voice configuration for. Read the word again, and you will hear it in American English voice.

If, as you stated, there could be multiple profiles active, you would hear the word read in British English Voice, because test2 didn't have voice specific configurations and the profile activated before that, called Test1, has British English as its voice.

Instead, what happened was that, when you activated test2, the test1 profile was immediately unloaded and, as test2 has no voice specific settings, the configuration on the default profile was then used.

This seems to confirm my impression that there may be only one active profile on a given moment, with the default profile being used as base for resolving settings that the active profile didn't specify.

The fact that a stack is chosen to achieve this implementation is an internal topic, and this is why I created a higher level abstraction that will give the caller the *** currently ** active profile, if there is one.

Sorry for the long text, and of course you are the maintainer here so I will end up naming the function whatever you decide, but I can not think on a better name, so if you could please provide it I will happily apply the change.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you demonstrated in your example, you cannot stack two profiles activated manually.
But you can stack 3 profiles (including default) in the following situation:

  • Profile 0: Default profile with English TTS and no indent reporting.
  • Profile 1: Application profile, e.g. Notepad++ profile with indent reporting; this profile is triggered when Notepad++ is focused
  • Profile 2: Manual profile with voice configured to Spanish TTS. And with a keyboard shortcut to enable it manually.
    Now if you go to Notepad++ and press the shortcut to activate the manual profile (profile 2), you will have both indent reported (Notepad++ profile option) and Spanish voice (manual profile option).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have a good point here.

This is getting confusing, because now NVDA behavior is not deterministic based on a given profile, since the stack below it can not be predicted. Anyways, I can not extend this to the dictionaries, because then one would never know exactly what to expect on pronunciation and substitution rules. I will delete this convenience function and access the top of stack directly when needed.

source/gui/__init__.py Outdated Show resolved Hide resolved
source/gui/__init__.py Outdated Show resolved Hide resolved
source/gui/settingsDialogs.py Outdated Show resolved Hide resolved
@@ -49,6 +52,12 @@ class SpeechDict(list):

fileName = None

def create(self, fileName):
if os.path.exists(fileName):
raise f"can not create dictionary backed by file {fileName}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please raise as an exception type. For a listing of built-in common exceptions see: https://docs.python.org/3/library/exceptions.html

I'd suggest using FileExistsError

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

source/speechDictHandler/dictFormatUpgrade.py Outdated Show resolved Hide resolved
@marlon-sousa
Copy link
Contributor Author

Hello @feerrenrut

Since this have been opened so many time ago, I will rebase with the latest master and see if anything else changed in the mean time.

I say that because this turned into an addon.

So I will this weekend:

  1. Rebase with latest master and make sure it works.
  2. Bring code improvements from the addon to the PR.
  3. Address things you pointed if they are still around.

As soon as it is ready I will let you know and we restart the review process again.

@AppVeyorBot
Copy link

See test results for failed build of commit 892959763c

@@ -628,6 +630,11 @@ def deleteProfile(self, name):
if trigger._profile == delProfile:
del self._suspendedTriggers[trigger]

def getActiveProfile(self):
if globalVars.appArgs.secure:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this should return a different value when in secure mode - while it is indeed impossible to create profiles or triggers when running securely triggers created in the configuration before it is copied to the system config are still applied.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you suggest?

My understanding is that if globalVars.appArgs.secure is on, then no custom profiles are allowed, so we return None to signalize that the default profile is used.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is that if globalVars.appArgs.secure is on, then no custom profiles are allowed,

That is not true. You can test as follows:

  1. Create a triggered profile for an application and change some settings there.
  2. Start NVDA providing --secure from the CLI.
  3. Check if the trigger for the configure profile has been applied or not.

What do you suggest?

This method should not do anything special when running with globalVars.appArgs.secure set to `true.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@feerrenrut Can you explain what globalVars.appArgs.secure does exactly?

@lukaszgo1 while I agree with you, in several places where globalVars.appArgs.secure is checked things like saving profiles seem to be disabled.

See, for example, the constructor of class ConfigManager in config/init.py

You will find the following piece of code:

self._shouldWriteProfile: bool = not (globalVars.appArgs.secure or globalVars.appArgs.launcher)

If I cannot save a profile, how am I supposed to switch to it?

Again, I would like to know what does this variable do. I couldn't find documentation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the user guide, advanced topics, command line options:
--secure: Secure mode: disables Python console, profile features such as creation, deletion, renaming profiles etc., update check, some checkboxes in the welcome dialog and in general settings category (e.g. Use NVDA during sign-in, save configuration after exit etc.), as well as logviewer and logging features (used often in secure screens). Note also that this command will disable the possibility to save settings in system config and the gesture map will not be saved on the disk.

The primary use case is when NVDA is run as the "System" user, eg during sign-on. Then the secure argument is set, search for isSecureDesktop = desktopName == "Winlogon" in nvda.pyw.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad. I should have looked first in the user guide instead ratter than spending more than 20 minutes inspecting the source code.

@lukaszgo1 thanks so much for pointing this out, it is now fixed and hopefully folks won a more elegant way than referencing [-1] every where.

@feerrenrut if there is anything else remaining let me know. Also, feel free to edit or ask some one to edit the documentation, I have done nearly my best but English is not my native language.

source/speechDictHandler/__init__.py Outdated Show resolved Hide resolved
source/speechDictHandler/__init__.py Outdated Show resolved Hide resolved
source/speechDictHandler/__init__.py Outdated Show resolved Hide resolved
source/speechDictHandler/__init__.py Outdated Show resolved Hide resolved
@lukaszgo1
Copy link
Contributor

If I cannot save a profile, how am I supposed to switch to it?

The same way you're supposed to customize settings for the secure config i.e. by configuring triggers however you like in your standard NVDA copy and then copying them into the system config from the general settings.

@CyrilleB79
Copy link
Collaborator

Hello @marlon-sousa

I'm just discovering the details of this PR/feature. I would like to discuss two main points.

Point 1: Whole dictionary override vs. entry override

If a dictionary is attached to a profile (e.g. myProfile), you have chosen to override the whole dictionary of the default profile. Since however the entries of the dictionary of the default profile may be useful everywhere, you have added the possibility to import entries from the dictionary of the default profile into the one of myProfile.
This approach has some limitations:

  • Each time you add or update an entry in the default profile dictionnary, you will need to import again the entries of the default profile into the myProfile dictionary.
  • If you ever make some clean-up in the default profile dictionary, you will need to perform the same clean-up in the profiles where you had imported default dic entries and thus remove manually each entry that was removed in the default dictionary.

On the contrary, have you considered to override the default dictionary entry by entry, i.e. loading default dic and then loading myProfile's dic, overiding existing entryes? This approach would be quite similar to what is done with symbol files where English symbol file is first loaded and then local (e.g. Portuguese) symbol file is loaded on top of English one, overriding duplicate entries.
This approach would eliminate the two limitations described above.
If you had not considered this approach, what do you think about it? If you had already considered it, please explain why you did not adopt it.

Point 2: Voice dictionary

In my view, the voice dictionary's goal is to fix the pronunciation of words that are not pronounced correctly by a voice. Thus I do not understand in which case tying a voice dictionary to a profile could be interesting.
Could you give a real-life example of the use of voice dictionaries tied to profiles?
Does the add-on have this capability? If yes, do you have any feedback on this feature?

Thanks.

@marlon-sousa
Copy link
Contributor Author

marlon-sousa commented Mar 24, 2021

Hello @marlon-sousa

I'm just discovering the details of this PR/feature. I would like to discuss two main points.

Point 1: Whole dictionary override vs. entry override

If a dictionary is attached to a profile (e.g. myProfile), you have chosen to override the whole dictionary of the default profile. Since however the entries of the dictionary of the default profile may be useful everywhere, you have added the possibility to import entries from the dictionary of the default profile into the one of myProfile.
This approach has some limitations:

  • Each time you add or update an entry in the default profile dictionnary, you will need to import again the entries of the default profile into the myProfile dictionary.
  • If you ever make some clean-up in the default profile dictionary, you will need to perform the same clean-up in the profiles where you had imported default dic entries and thus remove manually each entry that was removed in the default dictionary.

On the contrary, have you considered to override the default dictionary entry by entry, i.e. loading default dic and then loading myProfile's dic, overiding existing entryes? This approach would be quite similar to what is done with symbol files where English symbol file is first loaded and then local (e.g. Portuguese) symbol file is loaded on top of English one, overriding duplicate entries.
This approach would eliminate the two limitations described above.
If you had not considered this approach, what do you think about it? If you had already considered it, please explain why you did not adopt it.

Hello,

The rationale for the decision follows:

  1. Profile dictionaries is an advanced feature. In the majority of cases the default dictionary will handle everything nicely as it already does. If my needs for a profile are so so specific that I really need to use a specialized dictionary, then I likely don't want to have the default dictionary automatically synchronized. This is the case for dictionaries used in profiles attached to code and log visualization profiles, where several regexp based substitutions need to be made either to eliminate extra verbosity on application / text output or to facilitate some pronunciation stuff. These same rules applied to a daily profile would make text reading, at the minimum, insane. Many people oover time have used profiles to read in another language, because profile switching can change voice, speed, and other related stuff all at the same time. The default dictionary has been probelematic for those guys, because some times rules that do not apply for a language based profile just got in the way, and using voice dictionaries wouldn't help either because the default dictionary rules still apply. There are, based on feedback I have collected over the last year for the addon, other people using profile dictionaries to force translations for applications which does not provide them and doing a lot of other advanced things. In none of these scenarios the default dictionary is really important. Again, remember that profiles without a specific dictionary will just use the default one, so if you are setting a profile for proof reading or whatever and want full sync you just don't create dictionaries for it and there you have the full sync.
  2. But, eventually, you might want to have all or at least some entries automatically imported, specially some that make special sense for you. So, to offer you some facilities, you *** have *** a way of, *** optionally *** doing it with easy and confort by importing entries and choosing afterwards which one you want to keep or not. This is why the importter imports but do not save entries automatically.
  3. Being an advanced feature, configurability over automation was chosen, because the specific situation likely requires that one has what can or cannot happen under their control.
  4. In a future release, we can add a checkbox to the dialog which allows one to control if full sync (entry based sync) is enabled or disabled for the dictionary being edited. But, since you are free to create profiles with no custom dictionaries, I think this is covered by now.

Point 2: Voice dictionary

In my view, the voice dictionary's goal is to fix the pronunciation of words that are not pronounced correctly by a voice. Thus I do not understand in which case tying a voice dictionary to a profile could be interesting.
Could you give a real-life example of the use of voice dictionaries tied to profiles?
Does the add-on have this capability? If yes, do you have any feedback on this feature?

I can set two specific voices to say words a given way when coding, and make sure this does not apply when reading common text. Voices can have some peculiarities, so I would specify by voice some fixes. Although this is rare, again, remember that these are advanced configurations after all, and thus this gives flexibility at almost no extra cost.

Thanks.

@CyrilleB79
Copy link
Collaborator

  1. Profile dictionaries is an advanced feature. In the majority of cases the default dictionary will handle everything nicely as it already does. If my needs for a profile are so so specific that I really need to use a specialized dictionary, then I likely don't want to have the default dictionary automatically synchronized. This is the case for dictionaries used in profiles attached to code and log visualization profiles, where several regexp based substitutions need to be made either to eliminate extra verbosity on application / text output or to facilitate some pronunciation stuff.

I partly disagree with it regarding the example of code reading, where you may need specific entries (in the code dic) to read some keywords or specific code syntax, but you may also need common word entries (from the default dic) to read correctly the comments in the code.
Since you added the option to import entries from the default dic, that's probably because there was sometimes a need to use both default and profile dic entries.

  1. In a future release, we can add a checkbox to the dialog which allows one to control if full sync (entry based sync) is enabled or disabled for the dictionary being edited.

If today's choices do not prevent to implement full sync in the future, I would say that this PR is already a big progress for advanced users who want to configure each app with (or other profiles) with specific dic.

But, since you are free to create profiles with no custom dictionaries, I think this is covered by now.

No. The use case where the user want to remove a word from default profile dic is not cover. In this PR, the user has to remove the entry in the default profile dic and in all the dic where he had imported default profile dic. If entry-sync solution is implemented, the user has to remove only the entry from the default profile dic.

Point 2: Voice dictionary

In my view, the voice dictionary's goal is to fix the pronunciation of words that are not pronounced correctly by a voice. Thus I do not understand in which case tying a voice dictionary to a profile could be interesting.
Could you give a real-life example of the use of voice dictionaries tied to profiles?
Does the add-on have this capability? If yes, do you have any feedback on this feature?

I can set two specific voices to say words a given way when coding, and make sure this does not apply when reading common text. Voices can have some peculiarities, so I would specify by voice some fixes. Although this is rare, again, remember that these are advanced configurations after all, and thus this gives flexibility at almost no extra cost.

It has no extra cost, except NVDA code main tenability.
Again, if you have a real-life example, i.e. if you know of someone having just one entry in a voice dic tied to a specific profile, please describe it here. Thus this would help illustrate this use case.

@AppVeyorBot
Copy link

See test results for failed build of commit 668f59e316

@marlon-sousa
Copy link
Contributor Author

  1. Profile dictionaries is an advanced feature. In the majority of cases the default dictionary will handle everything nicely as it already does. If my needs for a profile are so so specific that I really need to use a specialized dictionary, then I likely don't want to have the default dictionary automatically synchronized. This is the case for dictionaries used in profiles attached to code and log visualization profiles, where several regexp based substitutions need to be made either to eliminate extra verbosity on application / text output or to facilitate some pronunciation stuff.

I partly disagree with it regarding the example of code reading, where you may need specific entries (in the code dic) to read some keywords or specific code syntax, but you may also need common word entries (from the default dic) to read correctly the comments in the code.
Since you added the option to import entries from the default dic, that's probably because there was sometimes a need to use both default and profile dic entries.

Yep, we agree, and this was the item 2 of my previous response. To recap, since this is an advanced option, I opted to let in the user's hand when, whether and how the sync should be done, while offering an elegant alternative for a case which can be common enough some times.

  1. In a future release, we can add a checkbox to the dialog which allows one to control if full sync (entry based sync) is enabled or disabled for the dictionary being edited.

If today's choices do not prevent to implement full sync in the future, I would say that this PR is already a big progress for advanced users who want to configure each app with (or other profiles) with specific dic.

But, since you are free to create profiles with no custom dictionaries, I think this is covered by now.

No. The use case where the user want to remove a word from default profile dic is not cover. In this PR, the user has to remove the entry in the default profile dic and in all the dic where he had imported default profile dic. If entry-sync solution is implemented, the user has to remove only the entry from the default profile dic.

Again, I don't disagree. The cost of removing manually entries for some dics comes with the benefit of putting sync on user's hands, greater power brings some times greater work.

Usually, default dictionaries will grow more than shrink, specially because now it will be possible to add entries that just make sense for specific cases to specific dics.

Personally, before the addon, I would find myself adding and removing entries because they would help me one day and get into my way on another, and I ended up adding and removing entries several times.

Now, by separating stuff, I almost don't have to remove entries.

But there is no right response, both points are valid.

Point 2: Voice dictionary

In my view, the voice dictionary's goal is to fix the pronunciation of words that are not pronounced correctly by a voice. Thus I do not understand in which case tying a voice dictionary to a profile could be interesting.
Could you give a real-life example of the use of voice dictionaries tied to profiles?
Does the add-on have this capability? If yes, do you have any feedback on this feature?

I can set two specific voices to say words a given way when coding, and make sure this does not apply when reading common text. Voices can have some peculiarities, so I would specify by voice some fixes. Although this is rare, again, remember that these are advanced configurations after all, and thus this gives flexibility at almost no extra cost.

It has no extra cost, except NVDA code main tenability.
Again, if you have a real-life example, i.e. if you know of someone having just one entry in a voice dic tied to a specific profile, please describe it here. Thus this would help illustrate this use case.

I can't do it. I just think that once we segregate any kind of persistent dictionaries we should segregate them all based on profiles ratter than mixing everything. Temporary dic does not account because oit is not persistent. A user should be able to make the choice, but again this is only my point of view.

Fixing upper case typo

Co-authored-by: Cyrille Bougot <cyrille.bougot2@laposte.net>
@XLTechie
Copy link
Contributor

XLTechie commented Mar 24, 2021 via email

@marlon-sousa
Copy link
Contributor Author

marlon-sousa commented Mar 24, 2021 via email

@feerrenrut
Copy link
Contributor

From NV Access' point of view, we'd prefer to get the design of this right before it is introduced. Despite being very hard work to think it through, it is entirely possible to do so without making code changes. Once something like this is introduced it can be quite hard to change. I think this would be a very valuable feature for power users, and is worth the effort. In order to come to a common understanding I'd suggest outlining the key user stories you are each thinking about. It may be that they are different in some areas and are common in others.

@cary-rowen
Copy link
Contributor

Is there the latest news about this PR?

@cary-rowen
Copy link
Contributor

I think this is a PR that benefits everyone I turn on separate profiles during reading to use specific voice characters and voice speeds, and because of the specificity of the book content I need to correct some readings using the regular expression rules of the voice dictionary that don't need to be corrected in other scenarios, so the PR is useful to me.
@marlon-sousa @feerrenrut

@XLTechie
Copy link
Contributor

XLTechie commented May 19, 2021 via email

@cary-rowen
Copy link
Contributor

@marlon-sousa
Do you have plans to update this PR?

@marlon-sousa
Copy link
Contributor Author

marlon-sousa commented Aug 30, 2021 via email

@cary-rowen
Copy link
Contributor

I agree with your point of view, and I think that such a feature should be merged as soon as possible to benefit more people, and it should not be blocked by the ideas of a few people.

@feerrenrut
Copy link
Contributor

I have not yet reviewed this PR because it seemed like discussion was ongoing.
The last message from @marlon-sousa indicates that this has stalled and they won't be trying to progress it any further.

I'm going to close this PR to make it clear to others that someone new may take this on if they wish to.
In order to make progress, a clear plan and reasoning for the approach will need to be provided.

@marlon-sousa if I have misunderstood, and you would like to work through feedback on this implementation please comment for me to re-open. You may need to provide more reasoning on your design decisions. Understanding your reasoning will make the review process easier.

@feerrenrut feerrenrut closed this Sep 1, 2021
@marlon-sousa
Copy link
Contributor Author

marlon-sousa commented Sep 1, 2021 via email

@cary-rowen
Copy link
Contributor

No one can come up with the final decision, only differences, and in the end a useful PR was closed. Many contributors will be disappointed because of this. An open source community should have a more positive and open attitude.
Even if some designs are not perfect yet, more people will benefit after the merger, and it is possible to improve them slowly in the future.

@feerrenrut
Copy link
Contributor

I understand there are different opinions on how to implement this feature. This isn't a project that NV Access has picked up, we are willing to provide advice on specific aspects as necessary, but the project must be driven by those developing it. This requires developing a functional specification, and getting stake holders to understand the trade-offs and agree to the approach. When there is a lot of discussion, this may also mean summarizing the current status, remaining questions etc. The easier you make it for us to understand and review your work, the more likely it is to be accepted.

As I said, if you have lost interest in trying to get this integrated, that is fine, I will leave this closed. But from briefly looking over the discussion here, it doesn't seem like the matter is settled, if you'd like to push this forward I can re-open it.

@feerrenrut feerrenrut added the Abandoned requested reports or updates are missing since more than 1 year, author or users are not available. label Sep 9, 2021
@CyrilleB79
Copy link
Collaborator

In case anyone wanting to take this PR again:

According to NV Access, user stories should be written and lead to a clear description of the resulting design with appropriate justifications.

And #11005 (comment) from @XLTechie which seemed to provide an interesting design suggestion has remained unanswered:

Wouldn't it be more reasonable to include now some checkbox for "Ignore default speech dictionary", and then do the entry based overriding that @CyrilleB79 suggests? It seems like it could cover both use cases: * It would allow any updates that occur in the default dictionary, to propagate to any interested profiles without further tedious and error-prone user action. * It would let profiles that specifically want to ignore the whole default dictionary, which is probably the more rare case, to do so easily. I have not read this PR's code, so I don't know where you would put such a checkbox, but presumably in whatever dialog lets you manipulate the profile's dictionary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Abandoned requested reports or updates are missing since more than 1 year, author or users are not available. enhancement feature/speech-dictionaries
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants