Repository: nvaccess/nvda

Issue:
Word 2016-365 installed with non-English language, with UIA is enabled, comments cannot be read
<!--
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:
Note, set office to use a language other than English.

approach 1:
1. Open the word document provided in the attachment.
2. When you arrow on a comment press insert+alt+c,

approach 2 - listing all comments in the elements list:
1. press insert+f7, when in the browse mode,
2. in the filter radio buttons category, find comments.

### Actual behavior:
When the first approach is used, the shortcut is not working, i.e. the comment was not read.
When you use the second approach, the following can be found in the log:

```
ERROR - queueHandler.flushQueue (19:54:49.137):
Error in func initElementType from eventQueue
Traceback (most recent call last):
  File "queueHandler.pyc", line 53, in flushQueue
  File "browseMode.pyc", line 902, in initElementType
  File "browseMode.pyc", line 922, in filter
  File "NVDAObjects\UIA\wordDocument.pyc", line 88, in label
TypeError: format() argument after ** must be a mapping, not NoneType
```

The comments are not listed

See code:
```
		if not obj.parent or obj.parent.name!='Comment':
			continue
```
The problem is that this object name is language sensitive i.e. in polish it is "Komentarz". So when the language in word interface is set to other than english, this condition is always true and NVDA doesn't see any comments even if there are some.

### Expected behavior:
The chomments should be listed and read, when nvda+alt+c, and when ins+f7 is pressed
### System configuration
#### NVDA installed/portable/running from source:
installed
#### NVDA version:
alpha-16768,a6f7fb40
#### Windows version:
windows 10, 1809, 17763
#### Name and version of other software in use when reproducing the issue:
microsoft office 365, 16.0.11231.20122
#### Other information about your system:
the sample files in the comments to follow
[Ęîëëîęâčóě_Ńňŕíĺ÷č÷.docx](https://github.com/nvaccess/nvda/files/2870461/Eieeieacoe_Nnril.c.docx)

### Other questions
#### Does the issue still occur after restarting your PC?
yes
#### Have you tried any other versions of NVDA?
no


Discussion:
@michaelDCurran 
@leonardder 
@josephsl 
@jage9 
This bug also occurs in NVDA 2019.1rc1
Related issues #9193  #9194 #9195

Please notice that Office (certainly excel) has changed the comments system. Renaming the old comments system as "notes", introducing a new comments system that supports replies.
I've looked into it and it turned out that this issue is caused by that condition:
```
		if not obj.parent or obj.parent.name!='Comment':
			continue
```
The problem is that this object name is language sensitive i.e. in polish it is "Komentarz". So when the language in word interface is set to other than english, this condition is always true and NVDA doesn't see any comments even if there are some.
Does that mean you can read the comments if MS Word is set to english language?
I didn't checked that, but I changed the word 'Comment' from condition to polish "Komentarz" and it worked well, so I suppose it would work with MS Word language set to english.
which is unacceptable, as i use word in russian, eventually polish when i am using it on another machine. 
can we implement all possible names for it, to avoid switching languages to english, as it is not an option?
This will not be possible I guess. There must be another solution for that.
> The problem is that this object name is language sensitive i.e. in polish it is "Komentarz". So when the language in word interface is set to other than english, this condition is always true and NVDA doesn't see any comments even if there are some.

Thanks for looking into this. Yes, we will have to look for another way to filter this. @michaelDCurran do you have any ideas. 

I'm going to modify the description and title of this issue to make it clear that language of office is important. 

Resolving patch:
diff --git a/source/NVDAObjects/UIA/wordDocument.py b/source/NVDAObjects/UIA/wordDocument.py
--- a/source/NVDAObjects/UIA/wordDocument.py
+++ b/source/NVDAObjects/UIA/wordDocument.py
@@ -1,7 +1,7 @@
-# A part of NonVisual Desktop Access (NVDA)
 # This file is covered by the GNU General Public License.
+# A part of NonVisual Desktop Access (NVDA)
 # See the file COPYING for more details.
-# Copyright (C) 2016-2020 NV Access Limited, Joseph Lee
+# Copyright (C) 2016-2021 NV Access Limited, Joseph Lee, Jakub Lukowicz
 
 from comtypes import COMError
 from collections import defaultdict
@@ -18,6 +18,8 @@
 from UIAUtils import *
 from . import UIA, UIATextInfo
 from NVDAObjects.window.winword import WordDocument as WordDocumentBase
+from scriptHandler import script
+
 
 """Support for Microsoft Word via UI Automation."""
 
@@ -67,15 +69,40 @@ def getCommentInfoFromPosition(position):
 	for index in range(UIAElementArray.length):
 		UIAElement=UIAElementArray.getElement(index)
 		UIAElement=UIAElement.buildUpdatedCache(UIAHandler.handler.baseCacheRequest)
-		obj=UIA(UIAElement=UIAElement)
-		if not obj.parent or obj.parent.name!='Comment':
-			continue
-		comment=obj.makeTextInfo(textInfos.POSITION_ALL).text
-		dateObj=obj.previous
-		date=dateObj.name
-		authorObj=dateObj.previous
-		author=authorObj.name
-		return dict(comment=comment,author=author,date=date)
+		typeID = UIAElement.GetCurrentPropertyValue(UIAHandler.UIA_AnnotationAnnotationTypeIdPropertyId)
+		# Use Annotation Type Comment if available
+		if typeID == UIAHandler.AnnotationType_Comment:
+			comment = UIAElement.GetCurrentPropertyValue(UIAHandler.UIA_NamePropertyId)
+			author = UIAElement.GetCurrentPropertyValue(UIAHandler.UIA_AnnotationAuthorPropertyId)
+			date = UIAElement.GetCurrentPropertyValue(UIAHandler.UIA_AnnotationDateTimePropertyId)
+			return dict(comment=comment, author=author, date=date)
+		else:
+			obj = UIA(UIAElement=UIAElement)
+			if (
+				not obj.parent
+				# Because the name of this object is language sensetive check if it has UIA Annotation Pattern
+				or not obj.parent.UIAElement.getCurrentPropertyValue(
+					UIAHandler.UIA_IsAnnotationPatternAvailablePropertyId
+				)
+			):
+				continue
+			comment = obj.makeTextInfo(textInfos.POSITION_ALL).text
+			tempObj = obj.previous.previous
+			authorObj = tempObj or obj.previous
+			author = authorObj.name
+			if not tempObj:
+				return dict(comment=comment, author=author)
+			dateObj = obj.previous
+			date = dateObj.name
+			return dict(comment=comment, author=author, date=date)
+
+
+def getPresentableCommentInfoFromPosition(commentInfo):
+	if "date" not in commentInfo:
+		# Translators: The message reported for a comment in Microsoft Word
+		return _("Comment: {comment} by {author}").format(**commentInfo)
+	# Translators: The message reported for a comment in Microsoft Word
+	return _("Comment: {comment} by {author} on {date}").format(**commentInfo)
 
 class CommentUIATextInfoQuickNavItem(TextAttribUIATextInfoQuickNavItem):
 	attribID=UIAHandler.UIA_AnnotationTypesAttributeId
@@ -84,8 +111,7 @@ class CommentUIATextInfoQuickNavItem(TextAttribUIATextInfoQuickNavItem):
 	@property
 	def label(self):
 		commentInfo=getCommentInfoFromPosition(self.textInfo)
-		# Translators: The message reported for a comment in Microsoft Word
-		return _("Comment: {comment} by {author} on {date}").format(**commentInfo)
+		return getPresentableCommentInfoFromPosition(commentInfo)
 
 class WordDocumentTextInfo(UIATextInfo):
 
@@ -329,31 +355,17 @@ def event_UIA_notification(self, activityId=None, **kwargs):
 			return
 		super(WordDocument, self).event_UIA_notification(**kwargs)
 
+	@script(
+		gesture="kb:NVDA+alt+c",
+		# Translators: a description for a script that reports the comment at the caret.
+		description=_("Reports the text of the comment where the System caret is located.")
+	)
 	def script_reportCurrentComment(self,gesture):
 		caretInfo=self.makeTextInfo(textInfos.POSITION_CARET)
-		caretInfo.expand(textInfos.UNIT_CHARACTER)
-		val=caretInfo._rangeObj.getAttributeValue(UIAHandler.UIA_AnnotationObjectsAttributeId)
-		if not val:
-			return
-		try:
-			UIAElementArray=val.QueryInterface(UIAHandler.IUIAutomationElementArray)
-		except COMError:
-			return
-		for index in range(UIAElementArray.length):
-			UIAElement=UIAElementArray.getElement(index)
-			UIAElement=UIAElement.buildUpdatedCache(UIAHandler.handler.baseCacheRequest)
-			obj=UIA(UIAElement=UIAElement)
-			if not obj.parent or obj.parent.name!='Comment':
-				continue
-			comment=obj.makeTextInfo(textInfos.POSITION_ALL).text
-			dateObj=obj.previous
-			date=dateObj.name
-			authorObj=dateObj.previous
-			author=authorObj.name
-			# Translators: The message reported for a comment in Microsoft Word
-			ui.message(_("{comment} by {author} on {date}").format(comment=comment,date=date,author=author))
-			return
-
-	__gestures={
-		"kb:NVDA+alt+c":"reportCurrentComment",
-	}
+		commentInfo = getCommentInfoFromPosition(caretInfo)
+		if commentInfo is not None:
+			ui.message(getPresentableCommentInfoFromPosition(commentInfo))
+		else:
+			# Translators: a message when there is no comment to report in Microsoft Word
+			ui.message(_("No comments"))
+		return


Test patch: