From 6275b56725edbcfbe2a3f863914b153fe3e73f68 Mon Sep 17 00:00:00 2001 From: Yannick Plassiard Date: Sat, 18 Jan 2020 05:32:15 +0100 Subject: [PATCH] Make the addon compatible with NVDA 2019.3 --- addon/globalPlugins/translate/__init__.py | 261 +++++++++++++--------- addon/locale/tr/LC_MESSAGES/nvda.po | 109 +++++---- buildVars.py | 6 +- 3 files changed, 225 insertions(+), 151 deletions(-) diff --git a/addon/globalPlugins/translate/__init__.py b/addon/globalPlugins/translate/__init__.py index 592f048..dbf9eca 100644 --- a/addon/globalPlugins/translate/__init__.py +++ b/addon/globalPlugins/translate/__init__.py @@ -16,20 +16,24 @@ import os, sys, time, codecs, re import globalVars import globalPluginHandler, logHandler, scriptHandler -import api, controlTypes -import ui, wx, gui, core, config, speech -import json -curDir = os.path.abspath(os.path.dirname(__file__)) +try: + import api, controlTypes + import ui, wx, gui + import core, config + import speech + from speech import * + import json + curDir = os.path.abspath(os.path.dirname(__file__)) + + sys.path.insert(0, curDir) + sys.path.insert(0, os.path.join(curDir, "html")) + import markupbase + import mtranslate + import addonHandler, languageHandler +except Exception as e: + logHanaler.log.exception("Failed to initialize translate addon", e) + raise e -sys.path.insert(0, curDir) -sys.path.insert(0, os.path.join(curDir, "html")) -import markupbase -if sys.version_info.major == 2: - import htmlentitydefs - import HTMLParser -import mtranslate -del sys.path[-1] -import addonHandler, languageHandler addonHandler.initTranslation() # # Global variables @@ -37,7 +41,7 @@ _translationCache = {} _nvdaSpeak = None -_nvdaGetSpeechTextForProperties = None +_nvdaGetPropertiesSpeech = None _gpObject = None _lastError = 0 _enableTranslation = False @@ -46,7 +50,7 @@ def translate(text): """translates the given text to the desired language. Stores the result into the cache so that the same translation does not asks Google servers too often. -""" + """ global _translationCache, _enableTranslation, _gpObject try: @@ -76,22 +80,23 @@ def translate(text): # -## Extracted and adapted from nvda/sources/speech.py +## Extracted and adapted from nvda/sources/speech/__init__.py # -def speak(speechSequence, **args): +def speak(speechSequence: SpeechSequence, + priority: Optional[Spri] = None): global _enableTranslation if _enableTranslation is False: - return _nvdaSpeak(speechSequence, **args) + return _nvdaSpeak(speechSequence=speechSequence, priority=priority) newSpeechSequence = [] for val in speechSequence: - if (sys.version_info.major == 2 and isinstance(val, basestring)) or (sys.version_info.major == 3 and isinstance(val, str)): + if isinstance(val, str): v = translate(val) newSpeechSequence.append(v if v is not None else val) else: newSpeechSequence.append(val) - _nvdaSpeak(newSpeechSequence, **args) + _nvdaSpeak(speechSequence=newSpeechSequence, priority=priority) # ## This is overloaded as well because the generated text may contain already translated text by @@ -99,22 +104,15 @@ def speak(speechSequence, **args): ## already localized, such as object's name, value, or description # -def getSpeechTextForProperties(reason=controlTypes.REASON_QUERY,**propertyValues): - oldTreeLevel = speech.oldTreeLevel - oldTableID = speech.oldTableID - oldRowNumber = speech.oldRowNumber - oldRowSpan = speech.oldRowSpan - oldColumnNumber = speech.oldColumnNumber - oldColumnSpan = speech.oldColumnSpan - - global _enableTranslation - - if not _enableTranslation: - return _nvdaGetSpeechTextForProperties(reason, **propertyValues) - textList=[] - name=propertyValues.get('name') +def getPropertiesSpeech( # noqa: C901 + reason = controlTypes.REASON_QUERY, + **propertyValues +): + global oldTreeLevel, oldTableID, oldRowNumber, oldRowSpan, oldColumnNumber, oldColumnSpan + textList: List[str] = [] + name: Optional[str] = propertyValues.get('name') if name: - textList.append(translate(name.replace("&", ""))) + textList.append(translate(name)) if 'role' in propertyValues: role=propertyValues['role'] speakRole=True @@ -124,15 +122,40 @@ def getSpeechTextForProperties(reason=controlTypes.REASON_QUERY,**propertyValues else: speakRole=False role=controlTypes.ROLE_UNKNOWN - value = propertyValues.get('value') if role not in controlTypes.silentValuesForRoles else None - cellCoordsText=propertyValues.get('cellCoordsText') - rowNumber=propertyValues.get('rowNumber') - columnNumber=propertyValues.get('columnNumber') - includeTableCellCoords=propertyValues.get('includeTableCellCoords',True) - if role==controlTypes.ROLE_CHARTELEMENT: - speakRole=False - roleText=propertyValues.get('roleText') - if speakRole and (roleText or reason not in (controlTypes.REASON_SAYALL,controlTypes.REASON_CARET,controlTypes.REASON_FOCUS) or not (name or value or cellCoordsText or rowNumber or columnNumber) or role not in controlTypes.silentRolesOnFocus) and (role!=controlTypes.ROLE_MATH or reason not in (controlTypes.REASON_CARET,controlTypes.REASON_SAYALL)): + value: Optional[str] = propertyValues.get('value') if role not in controlTypes.silentValuesForRoles else None + cellCoordsText: Optional[str] = propertyValues.get('cellCoordsText') + rowNumber = propertyValues.get('rowNumber') + columnNumber = propertyValues.get('columnNumber') + includeTableCellCoords = propertyValues.get('includeTableCellCoords', True) + + if role == controlTypes.ROLE_CHARTELEMENT: + speakRole = False + roleText: Optional[str] = propertyValues.get('roleText') + if ( + speakRole + and ( + roleText + or reason not in ( + controlTypes.REASON_SAYALL, + controlTypes.REASON_CARET, + controlTypes.REASON_FOCUS + ) + or not ( + name + or value + or cellCoordsText + or rowNumber + or columnNumber + ) + or role not in controlTypes.silentRolesOnFocus + ) + and ( + role != controlTypes.ROLE_MATH + or reason not in ( + controlTypes.REASON_CARET, + controlTypes.REASON_SAYALL + ) + )): textList.append(translate(roleText) if roleText else controlTypes.roleLabels[role]) if value: textList.append(translate(value)) @@ -140,11 +163,16 @@ def getSpeechTextForProperties(reason=controlTypes.REASON_QUERY,**propertyValues realStates=propertyValues.get('_states',states) negativeStates=propertyValues.get('negativeStates',set()) if states or negativeStates: - textList.extend(controlTypes.processAndLabelStates(role, realStates, reason, states, negativeStates)) - if 'description' in propertyValues: - textList.append(translate(propertyValues['description'])) - if 'keyboardShortcut' in propertyValues: - textList.append(propertyValues['keyboardShortcut']) + labelStates = controlTypes.processAndLabelStates(role, realStates, reason, states, negativeStates) + textList.extend(labelStates) + # sometimes description key is present but value is None + description: Optional[str] = propertyValues.get('description') + if description: + textList.append(translate(description)) + # sometimes keyboardShortcut key is present but value is None + keyboardShortcut: Optional[str] = propertyValues.get('keyboardShortcut') + if keyboardShortcut: + textList.append(keyboardShortcut) if includeTableCellCoords and cellCoordsText: textList.append(cellCoordsText) if cellCoordsText or rowNumber or columnNumber: @@ -154,87 +182,103 @@ def getSpeechTextForProperties(reason=controlTypes.REASON_QUERY,**propertyValues # Don't update the oldTableID if no tableID was given. if tableID and not sameTable: oldTableID = tableID - rowSpan = propertyValues.get("rowSpan") - columnSpan = propertyValues.get("columnSpan") - if rowNumber and (not sameTable or rowNumber != oldRowNumber or rowSpan != oldRowSpan): - rowHeaderText = propertyValues.get("rowHeaderText") - if rowHeaderText: - textList.append(translate(rowHeaderText)) - if includeTableCellCoords and not cellCoordsText: - # Translators: Speaks current row number (example output: row 3). - textList.append(_("row %s")%rowNumber) - if rowSpan>1 and columnSpan<=1: - # Translators: Speaks the row span added to the current row number (example output: through 5). - textList.append(_("through %s")%(rowNumber+rowSpan-1)) - oldRowNumber = rowNumber - oldRowSpan = rowSpan - if columnNumber and (not sameTable or columnNumber != oldColumnNumber or columnSpan != oldColumnSpan): - columnHeaderText = propertyValues.get("columnHeaderText") - if columnHeaderText: - textList.append(translate(columnHeaderText)) - if includeTableCellCoords and not cellCoordsText: - # Translators: Speaks current column number (example output: column 3). - textList.append(_("column %s")%columnNumber) - if columnSpan>1 and rowSpan<=1: - # Translators: Speaks the column span added to the current column number (example output: through 5). - textList.append(_("through %s")%(columnNumber+columnSpan-1)) - oldColumnNumber = columnNumber - oldColumnSpan = columnSpan - if includeTableCellCoords and not cellCoordsText and rowSpan>1 and columnSpan>1: - # Translators: Speaks the row and column span added to the current row and column numbers - # (example output: through row 5 column 3). - textList.append(_("through row {row} column {column}").format( - row=rowNumber+rowSpan-1, - column=columnNumber+columnSpan-1 - )) + # When fetching row and column span + # default the values to 1 to make further checks a lot simpler. + # After all, a table cell that has no rowspan implemented is assumed to span one row. + rowSpan = propertyValues.get("rowSpan") or 1 + columnSpan = propertyValues.get("columnSpan") or 1 + if rowNumber and (not sameTable or rowNumber != oldRowNumber or rowSpan != oldRowSpan): + rowHeaderText: Optional[str] = propertyValues.get("rowHeaderText") + if rowHeaderText: + textList.append(rowHeaderText) + if includeTableCellCoords and not cellCoordsText: + # Translators: Speaks current row number (example output: row 3). + rowNumberTranslation: str = _("row %s") % rowNumber + textList.append(rowNumberTranslation) + if rowSpan>1 and columnSpan<=1: + # Translators: Speaks the row span added to the current row number (example output: through 5). + rowSpanAddedTranslation: str = _("through %s") % (rowNumber + rowSpan - 1) + textList.append(rowSpanAddedTranslation) + oldRowNumber = rowNumber + oldRowSpan = rowSpan + if columnNumber and (not sameTable or columnNumber != oldColumnNumber or columnSpan != oldColumnSpan): + columnHeaderText: Optional[str] = propertyValues.get("columnHeaderText") + if columnHeaderText: + textList.append(translate(columnHeaderText)) + if includeTableCellCoords and not cellCoordsText: + # Translators: Speaks current column number (example output: column 3). + colNumberTranslation: str = _("column %s") % columnNumber + textList.append(colNumberTranslation) + if columnSpan>1 and rowSpan<=1: + # Translators: Speaks the column span added to the current column number (example output: through 5). + colSpanAddedTranslation: str = _("through %s") % (columnNumber + columnSpan - 1) + textList.append(colSpanAddedTranslation) + oldColumnNumber = columnNumber + oldColumnSpan = columnSpan + if includeTableCellCoords and not cellCoordsText and rowSpan>1 and columnSpan>1: + # Translators: Speaks the row and column span added to the current row and column numbers + # (example output: through row 5 column 3). + rowColSpanTranslation: str = _("through row {row} column {column}").format( + row=rowNumber + rowSpan - 1, + column=columnNumber + columnSpan - 1 + ) + textList.append(rowColSpanTranslation) rowCount=propertyValues.get('rowCount',0) columnCount=propertyValues.get('columnCount',0) if rowCount and columnCount: # Translators: Speaks number of columns and rows in a table (example output: with 3 rows and 2 columns). - textList.append(_("with {rowCount} rows and {columnCount} columns").format(rowCount=rowCount,columnCount=columnCount)) + rowAndColCountTranslation: str = _("with {rowCount} rows and {columnCount} columns").format( + rowCount=rowCount, + columnCount=columnCount + ) + textList.append(rowAndColCountTranslation) elif columnCount and not rowCount: # Translators: Speaks number of columns (example output: with 4 columns). - textList.append(_("with %s columns")%columnCount) + columnCountTransation: str = _("with %s columns") % columnCount + textList.append(columnCountTransation) elif rowCount and not columnCount: # Translators: Speaks number of rows (example output: with 2 rows). - textList.append(_("with %s rows")%rowCount) + rowCountTranslation: str = _("with %s rows") % rowCount + textList.append(rowCountTranslation) if rowCount or columnCount: # The caller is entering a table, so ensure that it is treated as a new table, even if the previous table was the same. oldTableID = None ariaCurrent = propertyValues.get('current', False) if ariaCurrent: try: - textList.append(controlTypes.isCurrentLabels[ariaCurrent]) + ariaCurrentLabel = controlTypes.isCurrentLabels[ariaCurrent] + textList.append(ariaCurrentLabel) except KeyError: log.debugWarning("Aria-current value not handled: %s"%ariaCurrent) - textList.append(controlTypes.isCurrentLabels[True]) - placeholder = propertyValues.get('placeholder', None) + ariaCurrentLabel = controlTypes.isCurrentLabels[True] + textList.append(ariaCurrentLabel) + placeholder: Optional[str] = propertyValues.get('placeholder', None) if placeholder: - textList.append(placeholder) + textList.append(translate(placeholder)) indexInGroup=propertyValues.get('positionInfo_indexInGroup',0) similarItemsInGroup=propertyValues.get('positionInfo_similarItemsInGroup',0) if 0\n" "Language-Team: cagrid@hotmail.com\n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.2\n" +"X-Generator: Poedit 2.2.3\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Poedit-SourceCharset: UTF-8\n" +"X-Poedit-Basepath: ../../../globalPlugins/translate\n" +"X-Poedit-SearchPath-0: .\n" -#. Translators: Speaks current row number (example output: row 3). -#: addon/globalPlugins/translate/__init__.py:147 +#: __init__.py:165 #, python-format msgid "row %s" msgstr "satır %s" -#. Translators: Speaks the row span added to the current row number (example output: through 5). -#. Translators: Speaks the column span added to the current column number (example output: through 5). -#: addon/globalPlugins/translate/__init__.py:150 addon/globalPlugins/translate/__init__.py:162 +#: __init__.py:168 __init__.py:180 #, python-format msgid "through %s" msgstr "%s boyunca" -#. Translators: Speaks current column number (example output: column 3). -#: addon/globalPlugins/translate/__init__.py:159 +#: __init__.py:177 #, python-format msgid "column %s" msgstr "sütun %s" -#. Translators: Speaks the row and column span added to the current row and column numbers -#. (example output: through row 5 column 3). -#: addon/globalPlugins/translate/__init__.py:168 +#: __init__.py:186 #, python-brace-format msgid "through row {row} column {column}" msgstr "satır {row} sütun {column} boyunca" -#. Translators: Speaks number of columns and rows in a table (example output: with 3 rows and 2 columns). -#: addon/globalPlugins/translate/__init__.py:176 +#: __init__.py:194 #, python-brace-format msgid "with {rowCount} rows and {columnCount} columns" msgstr "{rowCount} satır ve {columnCount} sütunlu" -#. Translators: Speaks number of columns (example output: with 4 columns). -#: addon/globalPlugins/translate/__init__.py:179 +#: __init__.py:197 #, python-format msgid "with %s columns" msgstr "%s sütunlu" -#. Translators: Speaks number of rows (example output: with 2 rows). -#: addon/globalPlugins/translate/__init__.py:182 +#: __init__.py:200 #, python-format msgid "with %s rows" msgstr "%s satırlı" -#. Translators: Spoken to indicate the position of an item in a group of items (such as a list). -#. {number} is replaced with the number of the item in the group. -#. {total} is replaced with the total number of items in the group. -#: addon/globalPlugins/translate/__init__.py:202 +#: __init__.py:220 #, python-brace-format msgid "{number} of {total}" msgstr "{number} bölü {total}" -#. Translators: Speaks the item level in treeviews (example output: level 2). -#: addon/globalPlugins/translate/__init__.py:208 addon/globalPlugins/translate/__init__.py:212 +#: __init__.py:226 __init__.py:230 #, python-format msgid "level %s" msgstr "seviye %s" -#: addon/globalPlugins/translate/__init__.py:230 +#: __init__.py:248 msgid "Translate" msgstr "Tercüme" -#: addon/globalPlugins/translate/__init__.py:271 +#: __init__.py:335 msgid "Translation enabled." msgstr "Çeviri etkin" -#: addon/globalPlugins/translate/__init__.py:273 +#: __init__.py:337 msgid "Translation disabled." msgstr "Çeviri devre dışı" -#: addon/globalPlugins/translate/__init__.py:275 +#: __init__.py:339 msgid "Enables translation to the desired language." msgstr "İstenen dile tercümeyi etkinleştirir" -#. Add-on description -#. Translators: Long description to be shown for this add-on on add-on information from add-ons manager -#: buildVars.py:20 -msgid "" -"Uses the Google Translate API to translate each spoken text to the desired language, on the fly.\n" -"This add-on requires an internet connection." -msgstr "" -"NVDA'nın konuşma sentezleyiciye gönderdiği her metni Google çeviri API'sini kullanarak istenen dile " -"tercüme eder.\n" -"Bu eklenti ınternet bağlantısı gerektirir." +#: __init__.py:343 +msgid "Press twice to delete all cached translations for all applications." +msgstr "Tüm uygulamalar için önbelleğe alınmış tüm çevirileri silmek için iki kez basın." + +#: __init__.py:356 +#| msgid "Translation enabled." +msgid "All translations have been deleted." +msgstr "Tüm çeviriler silindi." + +#: __init__.py:358 +msgid "Some caches failed to be removed." +msgstr "Önbellekdeki bazı şeyler silinemedi." + +#: __init__.py:359 +msgid "Remove all cached translations for all applications." +msgstr "Tüm uygulamalar için önbelleğe alınmış tüm çevirileri sil." + +#: __init__.py:365 +msgid "No focused application" +msgstr "Odaklanmış uygulama yok" + +#: __init__.py:368 +#, python-brace-format +msgid "Press twice to delete all translations for {app}" +msgstr "{app} için önbellekteki tüm çevirileri sil" + +#: __init__.py:380 +msgid "Error while deleting application's translation cache." +msgstr "Uygulamanın çeviri önbelleği silinirken hata oluştu." + +#: __init__.py:382 +#, python-brace-format +msgid "Translation cache for {app} has been deleted." +msgstr "{app} için çeviri önbelleği silindi." + +#: __init__.py:384 +#, python-brace-format +msgid "No saved translations for {app}" +msgstr "{app} için Kayıtlı çeviri yok" + +#: __init__.py:386 +msgid "Remove translation cache for the currently focused application" +msgstr "Odaklanan uygulama için çeviri önbelleğini sil" + +#~ msgid "" +#~ "Uses the Google Translate API to translate each spoken text to the desired language, on the fly.\n" +#~ "This add-on requires an internet connection." +#~ msgstr "" +#~ "NVDA'nın konuşma sentezleyiciye gönderdiği her metni Google çeviri API'sini kullanarak istenen dile tercüme eder.\n" +#~ "Bu eklenti ınternet bağlantısı gerektirir." diff --git a/buildVars.py b/buildVars.py index ce1cf62..81aaec5 100644 --- a/buildVars.py +++ b/buildVars.py @@ -20,7 +20,7 @@ "addon_description" : _("""Uses the Google Translate API to translate each spoken text to the desired language, on the fly. This add-on requires an internet connection."""), # version - "addon_version" : "2019.09.3", + "addon_version" : "2020.01", # Author(s) "addon_author" : u"Yannick PLASSIARD ", # URL for the add-on documentation support @@ -28,9 +28,9 @@ # Documentation file name "addon_docFileName" : "readme.html", # Minimum NVDA version supported (e.g. "2018.3") - "addon_minimumNVDAVersion" : "2018.3", + "addon_minimumNVDAVersion" : "2019.3", # Last NVDA version supported/tested (e.g. "2018.4", ideally more recent than minimum version) - "addon_lastTestedNVDAVersion" : "2019.2", + "addon_lastTestedNVDAVersion" : "2019.3", # Add-on update channel (default is stable or None) "addon_updateChannel" : "dev", }